/* Minification failed. Returning unminified contents.
(38076,11-12): run-time error JS1010: Expected identifier: .
(38076,11-12): run-time error JS1195: Expected expression: .
(52627,11-12): run-time error JS1010: Expected identifier: .
(52627,11-12): run-time error JS1195: Expected expression: .
(53103,61-62): run-time error JS1010: Expected identifier: .
(53103,61-62): run-time error JS1195: Expected expression: .
(53104,3-7): run-time error JS1034: Unmatched 'else'; no 'if' defined: else
(56165,9-10): run-time error JS1010: Expected identifier: .
(56165,9-10): run-time error JS1195: Expected expression: .
(57407,11-12): run-time error JS1010: Expected identifier: .
(57407,11-12): run-time error JS1195: Expected expression: .
(57969,11-12): run-time error JS1010: Expected identifier: .
(57969,11-12): run-time error JS1195: Expected expression: .
(58553,15-16): run-time error JS1010: Expected identifier: .
(58553,15-16): run-time error JS1195: Expected expression: .
(60121,15-16): run-time error JS1010: Expected identifier: .
(60121,15-16): run-time error JS1195: Expected expression: .
(60152,15-16): run-time error JS1010: Expected identifier: .
(60152,15-16): run-time error JS1195: Expected expression: .
(62010,11-12): run-time error JS1010: Expected identifier: .
(62010,11-12): run-time error JS1195: Expected expression: .
(62218,11-12): run-time error JS1010: Expected identifier: .
(62218,11-12): run-time error JS1195: Expected expression: .
(62253,7-8): run-time error JS1010: Expected identifier: .
(62253,7-8): run-time error JS1195: Expected expression: .
(62333,7-8): run-time error JS1010: Expected identifier: .
(62333,7-8): run-time error JS1195: Expected expression: .
(62353,11-12): run-time error JS1010: Expected identifier: .
(62353,11-12): run-time error JS1195: Expected expression: .
(68350,11-12): run-time error JS1010: Expected identifier: .
(68350,11-12): run-time error JS1195: Expected expression: .
(68468,11-12): run-time error JS1010: Expected identifier: .
(68468,11-12): run-time error JS1195: Expected expression: .
(68707,11-12): run-time error JS1010: Expected identifier: .
(68707,11-12): run-time error JS1195: Expected expression: .
(69045,7-8): run-time error JS1010: Expected identifier: .
(69045,7-8): run-time error JS1195: Expected expression: .
(69068,11-12): run-time error JS1010: Expected identifier: .
(69068,11-12): run-time error JS1195: Expected expression: .
(69441,15-16): run-time error JS1010: Expected identifier: .
(69441,15-16): run-time error JS1195: Expected expression: .
(69674,9-10): run-time error JS1010: Expected identifier: .
(69674,9-10): run-time error JS1195: Expected expression: .
(79510,7-8): run-time error JS1010: Expected identifier: .
(79510,7-8): run-time error JS1195: Expected expression: .
(96747,11-12): run-time error JS1010: Expected identifier: .
(96747,11-12): run-time error JS1195: Expected expression: .
(103680,15-16): run-time error JS1010: Expected identifier: .
(103680,15-16): run-time error JS1195: Expected expression: .
(103717,11-12): run-time error JS1010: Expected identifier: .
(103717,11-12): run-time error JS1195: Expected expression: .
(104280,11-12): run-time error JS1010: Expected identifier: .
(104280,11-12): run-time error JS1195: Expected expression: .
(105425,7-8): run-time error JS1010: Expected identifier: .
(105425,7-8): run-time error JS1195: Expected expression: .
(105573,7-8): run-time error JS1010: Expected identifier: .
(105573,7-8): run-time error JS1195: Expected expression: .
(105574,7-8): run-time error JS1010: Expected identifier: .
(105574,7-8): run-time error JS1195: Expected expression: .
(37580,17,37598,18): run-time error JS1314: Implicit property name must be identifier: _handleMax() {
                    // Disable options if max reached
                    if (settings.max) {
                        if (this.selectedCount >= +settings.max) {
                            this.optDiv.find('li').not('.hidden').each((ix, e) => {
                                if (!$(e).hasClass('selected')) {
                                    $(e).addClass('temporary-disabled disabled');
                                }
                            });
                        } else {
                            // Enable options back
                            this.optDiv.find('li').not('.hidden').each((ix, e) => {
                                if ($(e).hasClass('temporary-disabled')) {
                                    $(e).removeClass('temporary-disabled disabled');
                                }
                            });
                        }
                    }
                }
(37600,17,37618,18): run-time error JS1314: Implicit property name must be identifier: clearAll() {
                    const O = this;
                    if (!O.is_multi) return;
                    O.selAll = $('<p class="reset-all"><label></label></p>');
                    O.selAll.find('label')[0].innerText = settings.clearAlltext;
                    O.selAll.on('click', () => {
                        O.selAll.removeClass('selected');
                        O.toggSelAll(false, 1);
                        O.selectedCount = 0;
                        if (settings.max) {
                            O._handleMax();
                        }
                        if (settings.closeAfterClearAll) {
                            O.hideOpts();
                        }
                    });

                    O.optDiv.prepend(O.selAll);
                }
(106173,55-56): run-time error JS1013: Syntax error in regular expression: ,
(106172,49-50): run-time error JS1013: Syntax error in regular expression: ,
(108488,53-54): run-time error JS1013: Syntax error in regular expression: ,
 */
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "nprogress", "toastr", "lodash", "bootstrap", "bootstrap-hover-dropdown", "pjax", "cropper", "moment", "../../node_modules/moment/locale/ru.js", "../../bower_components/Sortable/knockout-sortable.js", "./componentLoader", "signalr", "js.cookie", "./utils/dateTimeUtils", "./utils/navBarUtils", "./utils/browserUtils", "./utils/webSocketUtils", "./utils/metrikaUtils", "./utils/imageZoomUtils", "./utils/cookieConsentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var nprogress = require("nprogress");
    var toastr = require("toastr");
    var _ = require("lodash");
    window["jQuery"] = window["$"] = $;
    window["AppUtils"] = {};
    window["AppComponents"] = {};
    if ($["event"].props.indexOf("dataTransfer") === -1) {
        $["event"].props.push("dataTransfer");
    }
    require("bootstrap");
    require("bootstrap-hover-dropdown");
    require("pjax");
    require("cropper");
    require("moment");
    require("../../node_modules/moment/locale/ru.js");
    require("../../bower_components/Sortable/knockout-sortable.js");
    require("./componentLoader");
    require("signalr");
    var viewModels = {'accountEmailChange': require('./viewModels/accountEmailChange.js'),'accountLogin': require('./viewModels/accountLogin.js'),'accountMyPage': require('./viewModels/accountMyPage.js'),'accountNotifications': require('./viewModels/accountNotifications.js'),'accountOrders': require('./viewModels/accountOrders.js'),'accountPasswordChange': require('./viewModels/accountPasswordChange.js'),'accountPhoneChange': require('./viewModels/accountPhoneChange.js'),'accountPrivacy': require('./viewModels/accountPrivacy.js'),'accountRecovery': require('./viewModels/accountRecovery.js'),'accountRegister': require('./viewModels/accountRegister.js'),'accountResetPassword': require('./viewModels/accountResetPassword.js'),'accountSecurity': require('./viewModels/accountSecurity.js'),'accountSettings': require('./viewModels/accountSettings.js'),'accountTotp': require('./viewModels/accountTotp.js'),'artEdit': require('./viewModels/artEdit.js'),'artView': require('./viewModels/artView.js'),'audiobookEditContent': require('./viewModels/audiobookEditContent.js'),'audiobookView': require('./viewModels/audiobookView.js'),'authorRatingReport': require('./viewModels/authorRatingReport.js'),'blackFriday': require('./viewModels/blackFriday.js'),'collectionComments': require('./viewModels/collectionComments.js'),'collectionEdit': require('./viewModels/collectionEdit.js'),'collectionEditContent': require('./viewModels/collectionEditContent.js'),'collectionView': require('./viewModels/collectionView.js'),'commentsView': require('./viewModels/commentsView.js'),'contestAssessment': require('./viewModels/contestAssessment.js'),'contestGroupEdit': require('./viewModels/contestGroupEdit.js'),'contestIndex': require('./viewModels/contestIndex.js'),'contestModerate': require('./viewModels/contestModerate.js'),'contestMyArts': require('./viewModels/contestMyArts.js'),'contestMyWork': require('./viewModels/contestMyWork.js'),'contestSelfJuryPreparation': require('./viewModels/contestSelfJuryPreparation.js'),'contestSettings': require('./viewModels/contestSettings.js'),'discountEdit': require('./viewModels/discountEdit.js'),'feedIndex': require('./viewModels/feedIndex.js'),'feedUnreadComments': require('./viewModels/feedUnreadComments.js'),'forumApply': require('./viewModels/forumApply.js'),'forumIndex': require('./viewModels/forumIndex.js'),'forumModerate': require('./viewModels/forumModerate.js'),'forumOrders': require('./viewModels/forumOrders.js'),'forumSettings': require('./viewModels/forumSettings.js'),'forumTicket': require('./viewModels/forumTicket.js'),'homeIndex': require('./viewModels/homeIndex.js'),'homeLibrary': require('./viewModels/homeLibrary.js'),'merchantDashboard': require('./viewModels/merchantDashboard.js'),'merchantDiscounts': require('./viewModels/merchantDiscounts.js'),'merchantReports': require('./viewModels/merchantReports.js'),'merchantStep1': require('./viewModels/merchantStep1.js'),'merchantStep3': require('./viewModels/merchantStep3.js'),'merchantStep4': require('./viewModels/merchantStep4.js'),'merchantStep5': require('./viewModels/merchantStep5.js'),'peopleIndex': require('./viewModels/peopleIndex.js'),'pmIndex': require('./viewModels/pmIndex.js'),'postEdit': require('./viewModels/postEdit.js'),'postView': require('./viewModels/postView.js'),'postsIndex': require('./viewModels/postsIndex.js'),'postsSettings': require('./viewModels/postsSettings.js'),'profileAwards': require('./viewModels/profileAwards.js'),'profileBaseEditPage': require('./viewModels/profileBaseEditPage.js'),'profileComments': require('./viewModels/profileComments.js'),'profileEditArts': require('./viewModels/profileEditArts.js'),'profileEditWorkSeries': require('./viewModels/profileEditWorkSeries.js'),'profileEditWorks': require('./viewModels/profileEditWorks.js'),'profileIndex': require('./viewModels/profileIndex.js'),'profileLibrary': require('./viewModels/profileLibrary.js'),'profileWorks': require('./viewModels/profileWorks.js'),'promoMigration': require('./viewModels/promoMigration.js'),'quiz1': require('./viewModels/quiz1.js'),'quiz2': require('./viewModels/quiz2.js'),'readerIndex': require('./viewModels/readerIndex.js'),'removeTotp': require('./viewModels/removeTotp.js'),'reportUserActivity': require('./viewModels/reportUserActivity.js'),'reportWorkStats': require('./viewModels/reportWorkStats.js'),'reviewEdit': require('./viewModels/reviewEdit.js'),'reviewIndex': require('./viewModels/reviewIndex.js'),'reviewManage': require('./viewModels/reviewManage.js'),'reviewView': require('./viewModels/reviewView.js'),'searchIndex': require('./viewModels/searchIndex.js'),'simpleViewModel': require('./viewModels/simpleViewModel.js'),'totp': require('./viewModels/totp.js'),'userHiddenAuthors': require('./viewModels/userHiddenAuthors.js'),'userRatingReport': require('./viewModels/userRatingReport.js'),'walletSettings': require('./viewModels/walletSettings.js'),'workBiblioNight': require('./viewModels/workBiblioNight.js'),'workDiscounts': require('./viewModels/workDiscounts.js'),'workEdit': require('./viewModels/workEdit.js'),'workEditChapter': require('./viewModels/workEditChapter.js'),'workEditContent': require('./viewModels/workEditContent.js'),'workEditSales': require('./viewModels/workEditSales.js'),'workGenre': require('./viewModels/workGenre.js'),'workGift': require('./viewModels/workGift.js'),'workImport': require('./viewModels/workImport.js'),'workRecommended': require('./viewModels/workRecommended.js'),'workSelectForm': require('./viewModels/workSelectForm.js'),'workSeries': require('./viewModels/workSeries.js'),'workSeriesEdit': require('./viewModels/workSeriesEdit.js'),'workSeriesView': require('./viewModels/workSeriesView.js'),'workTag': require('./viewModels/workTag.js'),'workUploads': require('./viewModels/workUploads.js'),'workView': require('./viewModels/workView.js')};
    var utils = {'ajaxUtils': require('./utils/ajaxUtils.js'),'authorRewardUtils': require('./utils/authorRewardUtils.js'),'browserUtils': require('./utils/browserUtils.js'),'commentLoadUtil': require('./utils/commentLoadUtil.js'),'commentUtils': require('./utils/commentUtils.js'),'cookieConsentUtils': require('./utils/cookieConsentUtils.js'),'cookieUtils': require('./utils/cookieUtils.js'),'dateTimeUtils': require('./utils/dateTimeUtils.js'),'devTools': require('./utils/devTools.js'),'exportBookUtils': require('./utils/exportBookUtils.js'),'giftCodeUtils': require('./utils/giftCodeUtils.js'),'imageUtils': require('./utils/imageUtils.js'),'imageZoomUtils': require('./utils/imageZoomUtils.js'),'indexedDbUtils': require('./utils/indexedDbUtils.js'),'localStorageUtils': require('./utils/localStorageUtils.js'),'merchantUtils': require('./utils/merchantUtils.js'),'metrikaUtils': require('./utils/metrikaUtils.js'),'navBarUtils': require('./utils/navBarUtils.js'),'oAuthUtils': require('./utils/oAuthUtils.js'),'postUtils': require('./utils/postUtils.js'),'profileUtils': require('./utils/profileUtils.js'),'readingProgressUtils': require('./utils/readingProgressUtils.js'),'richContentUtils': require('./utils/richContentUtils.js'),'socialUtils': require('./utils/socialUtils.js'),'stringUtils': require('./utils/stringUtils.js'),'vkIdUtils': require('./utils/vkIdUtils.js'),'webSocketUtils': require('./utils/webSocketUtils.js'),'windowUtils': require('./utils/windowUtils.js')};
    var customBindings = {'ko.btn': require('./customBindings/ko.btn.js'),'ko.checkPermissions': require('./customBindings/ko.checkPermissions.js'),'ko.checkedWithInit': require('./customBindings/ko.checkedWithInit.js'),'ko.datePicker': require('./customBindings/ko.datePicker.js'),'ko.dateRangePicker': require('./customBindings/ko.dateRangePicker.js'),'ko.drop': require('./customBindings/ko.drop.js'),'ko.froala': require('./customBindings/ko.froala.js'),'ko.readMore': require('./customBindings/ko.readMore.js'),'ko.richContent': require('./customBindings/ko.richContent.js'),'ko.select2': require('./customBindings/ko.select2.js'),'ko.sortable': require('./customBindings/ko.sortable.js'),'ko.sumoSelect': require('./customBindings/ko.sumoSelect.js'),'ko.time': require('./customBindings/ko.time.js'),'ko.valueWithInit': require('./customBindings/ko.valueWithInit.js')};
    var Cookies = require("js.cookie");
    window["Cookies"] = Cookies;
    require("jquery-mousewheel")($);
    var dateTimeUtils_1 = require("./utils/dateTimeUtils");
    var navBarUtils_1 = require("./utils/navBarUtils");
    var browserUtils_1 = require("./utils/browserUtils");
    var webSocketUtils_1 = require("./utils/webSocketUtils");
    var metrikaUtils_1 = require("./utils/metrikaUtils");
    var imageZoomUtils_1 = require("./utils/imageZoomUtils");
    var cookieConsentUtils_1 = require("./utils/cookieConsentUtils");
    var SiteApp = (function () {
        function SiteApp() {
            this.isKoInit = false;
            this.isInitialized = false;
        }
        SiteApp.prototype.reset = function () {
            this.isInitialized = false;
        };
        SiteApp.prototype.setOptions = function (options) {
            this.isAuthenticated = options.isAuthenticated;
            this.emailConfirmed = options.emailConfirmed;
            this.rootUrl = options.rootUrl;
            this.userId = options.userId;
            this.prodEnv = options.prodEnv;
            this.isApp = options.isApp;
            this.statsApiUrl = options.statsApiUrl;
            this.yaCounterId = options.yaCounterId;
            this.yaKassaBlocked = options.yaKassaBlocked;
            if (!this.isAuthenticated) {
                $(document.body).addClass("no-auth");
            }
        };
        SiteApp.prototype.createViewModel = function (page, options) {
            if (!page)
                return {};
            var viewModel = viewModels[page];
            if (viewModel === undefined || viewModel === null) {
                throw new Error("ViewModel not found: " + page);
            }
            return new viewModel.default(options);
        };
        SiteApp.prototype.initUtils = function () {
            var _this = this;
            navBarUtils_1.default.init();
            if (this.isInitialized)
                return;
            dateTimeUtils_1.default.displayTime();
            if (this.isAuthenticated) {
                webSocketUtils_1.default.registerServiceWorker();
                webSocketUtils_1.default.initCrossTab();
            }
            cookieConsentUtils_1.default.init();
            metrikaUtils_1.default.init("full");
            imageZoomUtils_1.default.init();
            $(document).on("ready", function () {
                _this.setAvaMenu();
                var $updownScroll = $("#updownscroll"), $window = $(window);
                var lastScrollPosition = 0;
                var isScrolling = false;
                $updownScroll.on("click", function () {
                    if ($updownScroll.hasClass("scroll-down")) {
                        $updownScroll.removeClass("scroll-down");
                        isScrolling = true;
                        $("html, body").stop().animate({ scrollTop: lastScrollPosition }, {
                            duration: "fast",
                            always: function () {
                                isScrolling = false;
                            }
                        });
                        lastScrollPosition = 0;
                    }
                    else {
                        $updownScroll.addClass("scroll-down");
                        lastScrollPosition = $window.scrollTop();
                        isScrolling = true;
                        $("html, body").stop().animate({ scrollTop: 0 }, {
                            duration: "fast",
                            always: function () {
                                isScrolling = false;
                            }
                        });
                    }
                });
                $window.on("scroll", function () {
                    var position = $window.scrollTop();
                    if (position > 300) {
                        $updownScroll.addClass("active");
                    }
                    else if (lastScrollPosition === 0 && !isScrolling) {
                        $updownScroll.removeClass("active");
                    }
                    if (lastScrollPosition < position) {
                        $updownScroll.removeClass("scroll-down");
                    }
                });
                if (!_this.isAuthenticated) {
                    if ($("#authModal")[0]) {
                        $("#authModal").modal({ show: false });
                        var loginViewModel = _this.createViewModel("accountLogin", {});
                        ko.applyBindings(loginViewModel, $("#authModal")[0]);
                    }
                }
            });
        };
        SiteApp.prototype.init = function (page, options) {
            var _this = this;
            $.pjax.defaults.timeout = 10000;
            $.pjax.defaults.maxCacheLength = 0;
            ko["options"].deferUpdates = true;
            if (window["kendo"]) {
                window["kendo"].culture("ru-RU");
            }
            toastr.options.timeOut = 10000;
            toastr.options.extendedTimeOut = 5000;
            window.alert = function (message) {
                toastr.error(message, "Произошла ошибка");
            };
            // Выключаем pjax в IE
            if (browserUtils_1.default.isIE()) {
                $.ajaxSetup({ cache: false });
            }
            if ($.support.pjax) {
                $(document).on("click", "[data-pjax] a, a[data-pjax]", function (event) {
                    var $el = $(this);
                    var $container;
                    if ($el.attr("data-pjax-custom")) {
                        if ($el.attr("data-pjax-container")) {
                            $container = $($el.attr("data-pjax-container"));
                        }
                        else {
                            $container = $el.closest("[data-pjax-container]");
                        }
                    }
                    else {
                        $container = $("#pjax-container");
                    }
                    $.pjax.click(event, { container: $container });
                });
            }
            nprogress.configure({
                parent: ".brand-logo",
                showSpinner: true,
                template: "<div class='bar' role='bar'></div>" +
                    "<div class='loading-indicator' role='spinner'>" +
                    "<div class='la-timer la-dark'><div></div></div></div>"
            });
            window["nprogress"] = nprogress;
            if (this.isInitialized)
                return;
            this.initUtils();
            // Dispose previous view model
            if (this.viewModel && _.isFunction(this.viewModel.dispose)) {
                this.viewModel.dispose();
            }
            this.viewModel = this.createViewModel(page, options);
            this.isInitialized = true;
            if (!this.isKoInit) {
                window["ko"] = ko;
                window["viewModel"] = this.viewModel;
                var isAccountLayoutCollapsed = $(".account-layout:not(.aside-collapsed)")[0] !== undefined;
                $(document)
                    .on("pjax:send", function () {
                    nprogress.start();
                    isAccountLayoutCollapsed = $(".account-layout:not(.aside-collapsed)")[0] !== undefined;
                })
                    .on("pjax:success", function (xhr, options) {
                    try {
                        ko.applyBindingsToDescendants(_this.viewModel, xhr.target);
                    }
                    catch (e) {
                        console.error(e);
                    }
                })
                    .on("pjax:complete", function (xhr, options) {
                    nprogress.done();
                })
                    .on("pjax:end", function () {
                    _this.initUtils();
                    if (isAccountLayoutCollapsed) {
                        $("#aside-toggle").trigger("click");
                    }
                });
                ko.applyBindings(this.viewModel, $("#pjax-container")[0]);
                if ($(".topnavbar-wrapper")[0]) {
                    ko.applyBindings(this.viewModel, $(".topnavbar-wrapper")[0]);
                }
                this.isKoInit = true;
            }
            ;
        };
        SiteApp.prototype.showLoginModal = function () {
            try {
                metrikaUtils_1.default.reachGoal("showLoginForm");
            }
            catch (ex) {
                console.error(ex);
            }
            try {
                if (this.canBeHandledByApp()) {
                    this.getAppMobileHandler().handleLogin();
                    return;
                }
            }
            catch (e) {
                console.error(e);
            }
            $("#authModal").modal("toggle");
        };
        SiteApp.prototype.ensureAuth = function (onlyIfEmailConfirmed) {
            if (onlyIfEmailConfirmed === void 0) { onlyIfEmailConfirmed = false; }
            if (!this.isAuthenticated) {
                this.showLoginModal();
                return false;
            }
            if (onlyIfEmailConfirmed && !this.emailConfirmed) {
                var modal = window["AppComponents"].ModalDialog;
                var confirmEmailUrl = this.rootUrl + "account/settings";
                modal.show({
                    title: "Ошибка",
                    message: "\u0412\u044B \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B\u0438 \u0441\u0432\u043E\u0439 \u0430\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B. <a href=\"" + confirmEmailUrl + "\">\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C</a>",
                    type: 3
                });
                return false;
            }
            return true;
        };
        SiteApp.prototype.getAppMobileHandler = function () {
            return window["authorTodayMobileHandler"];
        };
        SiteApp.prototype.canBeHandledByApp = function () {
            return this.isApp
                && this.getAppMobileHandler() !== undefined
                && this.getAppMobileHandler() !== null;
        };
        SiteApp.prototype.logOff = function () {
            try {
                if (this.canBeHandledByApp()) {
                    this.getAppMobileHandler().handleLogout();
                    return;
                }
            }
            catch (e) {
                console.error(e);
            }
            $("#logoffForm").submit();
        };
        /** Настраивает меню аватарки */
        SiteApp.prototype.setAvaMenu = function () {
            var topAvaMenu = $('.top-ava-menu').hide();
            $('.user-dropdown-toggle').hover(function (e) {
                topAvaMenu.show();
            });
            $('.dropdown').find('.dropdown-menu-links').find('li:eq(1)').hover(function (e) {
                topAvaMenu.hide();
            });
        };
        return SiteApp;
    }());
    ;
    window["app"] = new SiteApp();
});

},{"../../bower_components/Sortable/knockout-sortable.js":183,"../../node_modules/moment/locale/ru.js":218,"./componentLoader":2,"./customBindings/ko.btn.js":29,"./customBindings/ko.checkPermissions.js":30,"./customBindings/ko.checkedWithInit.js":31,"./customBindings/ko.datePicker.js":32,"./customBindings/ko.dateRangePicker.js":33,"./customBindings/ko.drop.js":34,"./customBindings/ko.froala.js":35,"./customBindings/ko.readMore.js":36,"./customBindings/ko.richContent.js":37,"./customBindings/ko.select2.js":38,"./customBindings/ko.sortable.js":39,"./customBindings/ko.sumoSelect.js":40,"./customBindings/ko.time.js":41,"./customBindings/ko.valueWithInit.js":42,"./utils/ajaxUtils.js":45,"./utils/authorRewardUtils.js":46,"./utils/browserUtils":47,"./utils/browserUtils.js":47,"./utils/commentLoadUtil.js":48,"./utils/commentUtils.js":49,"./utils/cookieConsentUtils":50,"./utils/cookieConsentUtils.js":50,"./utils/cookieUtils.js":51,"./utils/dateTimeUtils":52,"./utils/dateTimeUtils.js":52,"./utils/devTools.js":53,"./utils/exportBookUtils.js":54,"./utils/giftCodeUtils.js":55,"./utils/imageUtils.js":56,"./utils/imageZoomUtils":57,"./utils/imageZoomUtils.js":57,"./utils/indexedDbUtils.js":58,"./utils/localStorageUtils.js":59,"./utils/merchantUtils.js":60,"./utils/metrikaUtils":61,"./utils/metrikaUtils.js":61,"./utils/navBarUtils":62,"./utils/navBarUtils.js":62,"./utils/oAuthUtils.js":63,"./utils/postUtils.js":64,"./utils/profileUtils.js":65,"./utils/readingProgressUtils.js":66,"./utils/richContentUtils.js":67,"./utils/socialUtils.js":68,"./utils/stringUtils.js":69,"./utils/vkIdUtils.js":70,"./utils/webSocketUtils":71,"./utils/webSocketUtils.js":71,"./utils/windowUtils.js":72,"./viewModels/accountEmailChange.js":73,"./viewModels/accountLogin.js":74,"./viewModels/accountMyPage.js":75,"./viewModels/accountNotifications.js":76,"./viewModels/accountOrders.js":77,"./viewModels/accountPasswordChange.js":78,"./viewModels/accountPhoneChange.js":79,"./viewModels/accountPrivacy.js":80,"./viewModels/accountRecovery.js":81,"./viewModels/accountRegister.js":82,"./viewModels/accountResetPassword.js":83,"./viewModels/accountSecurity.js":84,"./viewModels/accountSettings.js":85,"./viewModels/accountTotp.js":86,"./viewModels/artEdit.js":87,"./viewModels/artView.js":88,"./viewModels/audiobookEditContent.js":89,"./viewModels/audiobookView.js":90,"./viewModels/authorRatingReport.js":91,"./viewModels/blackFriday.js":94,"./viewModels/collectionComments.js":95,"./viewModels/collectionEdit.js":96,"./viewModels/collectionEditContent.js":97,"./viewModels/collectionView.js":98,"./viewModels/commentsView.js":99,"./viewModels/contestAssessment.js":100,"./viewModels/contestGroupEdit.js":101,"./viewModels/contestIndex.js":102,"./viewModels/contestModerate.js":103,"./viewModels/contestMyArts.js":104,"./viewModels/contestMyWork.js":105,"./viewModels/contestSelfJuryPreparation.js":106,"./viewModels/contestSettings.js":107,"./viewModels/discountEdit.js":108,"./viewModels/feedIndex.js":109,"./viewModels/feedUnreadComments.js":110,"./viewModels/forumApply.js":111,"./viewModels/forumIndex.js":112,"./viewModels/forumModerate.js":113,"./viewModels/forumOrders.js":114,"./viewModels/forumSettings.js":115,"./viewModels/forumTicket.js":116,"./viewModels/homeIndex.js":117,"./viewModels/homeLibrary.js":118,"./viewModels/merchantDashboard.js":119,"./viewModels/merchantDiscounts.js":120,"./viewModels/merchantReports.js":121,"./viewModels/merchantStep1.js":122,"./viewModels/merchantStep3.js":123,"./viewModels/merchantStep4.js":124,"./viewModels/merchantStep5.js":125,"./viewModels/peopleIndex.js":126,"./viewModels/pmIndex.js":127,"./viewModels/postEdit.js":128,"./viewModels/postView.js":129,"./viewModels/postsIndex.js":130,"./viewModels/postsSettings.js":131,"./viewModels/profileAwards.js":132,"./viewModels/profileBaseEditPage.js":133,"./viewModels/profileComments.js":134,"./viewModels/profileEditArts.js":135,"./viewModels/profileEditWorkSeries.js":136,"./viewModels/profileEditWorks.js":137,"./viewModels/profileIndex.js":138,"./viewModels/profileLibrary.js":139,"./viewModels/profileWorks.js":140,"./viewModels/promoMigration.js":141,"./viewModels/quiz1.js":142,"./viewModels/quiz2.js":143,"./viewModels/readerIndex.js":144,"./viewModels/removeTotp.js":145,"./viewModels/reportUserActivity.js":146,"./viewModels/reportWorkStats.js":147,"./viewModels/reviewEdit.js":148,"./viewModels/reviewIndex.js":149,"./viewModels/reviewManage.js":150,"./viewModels/reviewView.js":151,"./viewModels/searchIndex.js":152,"./viewModels/simpleViewModel.js":153,"./viewModels/totp.js":154,"./viewModels/userHiddenAuthors.js":155,"./viewModels/userRatingReport.js":156,"./viewModels/walletSettings.js":157,"./viewModels/workBiblioNight.js":158,"./viewModels/workDiscounts.js":159,"./viewModels/workEdit.js":160,"./viewModels/workEditChapter.js":161,"./viewModels/workEditContent.js":162,"./viewModels/workEditSales.js":163,"./viewModels/workGenre.js":164,"./viewModels/workGift.js":165,"./viewModels/workImport.js":166,"./viewModels/workRecommended.js":167,"./viewModels/workSelectForm.js":168,"./viewModels/workSeries.js":169,"./viewModels/workSeriesEdit.js":170,"./viewModels/workSeriesView.js":171,"./viewModels/workTag.js":172,"./viewModels/workUploads.js":173,"./viewModels/workView.js":174,"bootstrap":185,"bootstrap-hover-dropdown":184,"cropper":175,"jquery":214,"jquery-mousewheel":213,"js.cookie":215,"knockout":191,"lodash":216,"moment":219,"nprogress":193,"pjax":188,"signalr":195,"toastr":199}],2:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "lodash", "./utils/AjaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var _ = require("lodash");
    var AjaxUtils_1 = require("./utils/AjaxUtils");
    var componentViewModels = {'addToLibraryButton': require('./components/addToLibraryButton.js'),'asideWidget': require('./components/asideWidget.js'),'buyButton': require('./components/buyButton.js'),'chatRemoveButton': require('./components/chatRemoveButton.js'),'commentFormV1': require('./components/commentFormV1.js'),'deleteUserForm': require('./components/deleteUserForm.js'),'disputedItems': require('./components/disputedItems.js'),'editAvatar': require('./components/editAvatar.js'),'editProfileBg': require('./components/editProfileBg.js'),'feedbackForm': require('./components/feedbackForm.js'),'hideButton': require('./components/hideButton.js'),'ignoreListButton': require('./components/ignoreListButton.js'),'libraryButton': require('./components/libraryButton.js'),'likeButton': require('./components/likeButton.js'),'markButton': require('./components/markButton.js'),'modalDialog': require('./components/modalDialog.js'),'moderateCommentForm': require('./components/moderateCommentForm.js'),'notifications': require('./components/notifications.js'),'subToCollectionButton': require('./components/subToCollectionButton.js'),'subToSeriesButton': require('./components/subToSeriesButton.js'),'subscribeButton': require('./components/subscribeButton.js'),'userAvatar': require('./components/userAvatar.js'),'videoPlayer': require('./components/videoPlayer.js'),'worksWidget': require('./components/worksWidget.js')};
    var componentLoader = {
        getConfig: function (name, callback) {
            var componentName = _.camelCase(name);
            var viewModelConstructor = componentViewModels[componentName];
            if (viewModelConstructor === undefined) {
                throw new Error("Unable to find view model for component \"" + componentName + "\"");
            }
            callback({
                viewModel: {
                    createViewModel: function (params, componentInfo) {
                        var viewModel = new viewModelConstructor.default(params, componentInfo.element, componentInfo.templateNodes);
                        var appComponentName = _.upperFirst(componentName);
                        window["AppComponents"][appComponentName] = viewModel;
                        return viewModel;
                    }
                },
                template: { fromUrl: componentName },
                synchronous: true
            });
        },
        loadTemplate: function (name, templateConfig, callback) {
            if (templateConfig.fromUrl) {
                AjaxUtils_1.AjaxUtils.getTemplate(templateConfig.fromUrl).done(function (result) {
                    if (_.isString(result)) {
                        ko.components.defaultLoader.loadTemplate(name, result, callback);
                    }
                });
            }
            else {
                callback(null);
            }
        }
    };
    ko.components.loaders.unshift(componentLoader);
});

},{"./components/addToLibraryButton.js":3,"./components/asideWidget.js":4,"./components/buyButton.js":7,"./components/chatRemoveButton.js":8,"./components/commentFormV1.js":9,"./components/deleteUserForm.js":10,"./components/disputedItems.js":11,"./components/editAvatar.js":12,"./components/editProfileBg.js":13,"./components/feedbackForm.js":14,"./components/hideButton.js":15,"./components/ignoreListButton.js":16,"./components/libraryButton.js":17,"./components/likeButton.js":18,"./components/markButton.js":19,"./components/modalDialog.js":20,"./components/moderateCommentForm.js":21,"./components/notifications.js":22,"./components/subToCollectionButton.js":23,"./components/subToSeriesButton.js":24,"./components/subscribeButton.js":25,"./components/userAvatar.js":26,"./components/videoPlayer.js":27,"./components/worksWidget.js":28,"./utils/AjaxUtils":44,"knockout":191,"lodash":216}],3:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "../utils/ajaxUtils", "../utils/metrikaUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var metrikaUtils_1 = require("../utils/metrikaUtils");
    var AddToLibraryButtonComponent = (function (_super) {
        __extends(AddToLibraryButtonComponent, _super);
        function AddToLibraryButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.libraryId = ko.observable();
            this.isActive = ko.pureComputed(function () {
                return !!_this.libraryId();
            });
            this.libraryId(params.libraryId);
            this.workId = params.workId;
            this.inlineBtn = params.inlineBtn;
        }
        AddToLibraryButtonComponent.prototype.toggle = function () {
            var _this = this;
            if (!app.ensureAuth()) {
                return;
            }
            if (this.processing())
                return;
            this.processing(true);
            if (this.isActive()) {
                ajaxUtils_1.AjaxUtils.post("work/removeFromLibrary", { id: this.libraryId() })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.libraryId(null);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
            else {
                ajaxUtils_1.AjaxUtils.post("work/addToLibrary", { workId: this.workId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    try {
                        metrikaUtils_1.default.reachGoal("addToLibrary", { workId: _this.workId });
                    }
                    catch (ex) { }
                    _this.libraryId(result.data);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
        };
        return AddToLibraryButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("add-to-library-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AddToLibraryButtonComponent;
});

},{"../utils/ajaxUtils":45,"../utils/metrikaUtils":61,"./base/BaseComponent":5,"knockout":191}],4:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "lodash", "../utils/localStorageUtils", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var AsideWidgetComponent = (function (_super) {
        __extends(AsideWidgetComponent, _super);
        function AsideWidgetComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.isLoading = ko.observable(true);
            this.widgetHtml = ko.observable();
            this.url = params.url;
            this.title = params.title;
            this.requestParams = params.rParams || {};
            this.localeStorageParams = params.lsParams || {};
            this.css = params.css;
            var cache = params.cache || false;
            _.each(this.localeStorageParams, function (rKey, lsKey) {
                _this.requestParams[rKey] = localStorageUtils_1.default.get(lsKey);
            });
            ajaxUtils_1.AjaxUtils.get(this.url, this.requestParams, cache)
                .done(function (result) {
                if (!result.isSuccessful) {
                    console.warn(result.messages[0]);
                    $(element).hide();
                    return;
                }
                _this.widgetHtml(result.data.html);
                setTimeout(function () {
                    $(element).find(".widget-content").addClass("in");
                });
            }).always(function () {
                _this.isLoading(false);
            });
        }
        return AsideWidgetComponent;
    }(baseComponent_1.default));
    ko.components.register("aside-widget", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AsideWidgetComponent;
});

},{"../utils/ajaxUtils":45,"../utils/localStorageUtils":59,"./base/baseComponent":6,"jquery":214,"knockout":191,"lodash":216}],5:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "../../viewModels/base/baseViewModel", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseViewModel_1 = require("../../viewModels/base/baseViewModel");
    var ko = require("knockout");
    var BaseComponent = (function (_super) {
        __extends(BaseComponent, _super);
        function BaseComponent(params, element, templateNodes) {
            _super.call(this);
            this.processing = ko.observable(false);
            this.params = params;
            this.element = element;
            this.templateNodes = templateNodes;
        }
        return BaseComponent;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = BaseComponent;
});

},{"../../viewModels/base/baseViewModel":92,"knockout":191}],6:[function(require,module,exports){
arguments[4][5][0].apply(exports,arguments)
},{"../../viewModels/base/baseViewModel":92,"dup":5,"knockout":191}],7:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "jquery", "lodash", "numeral", "./modalDialog", "moment", "jquery.countdown", "../utils/merchantUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var numeral = require("numeral");
    var modalDialog_1 = require("./modalDialog");
    var moment = require("moment");
    require("jquery.countdown");
    var merchantUtils_1 = require("../utils/merchantUtils");
    var BuyButtonComponent = (function (_super) {
        __extends(BuyButtonComponent, _super);
        function BuyButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.priceFormat = "0,0.[00]";
            this.discount = ko.observable();
            this.priceText = ko.observable();
            this.mode = ko.observable("work");
            this.stage = ko.observable("startBuyingWork");
            this.rewardOptions = [10, 25, 50, 75, 100, 150];
            this.isCustomRewardValue = ko.observable(false);
            this.minReward = 10;
            this.maxReward = 15000;
            this.rewardStep = 10;
            this.savePaymentMethod = ko.observable();
            this.savePaymentMethodDontAsk = ko.observable();
            this.selectedPaymentMethod = ko.observable();
            this.rewardValue = ko.observable(25).extend({
                required: {
                    onlyIf: function () {
                        return (_this.stage() === "setRewardAmount" || _this.stage() === "setBalanceAmount") && _this.isCustomRewardValue();
                    }
                },
                min: this.minReward,
                max: this.maxReward
            });
            this.rewardValueText = ko.pureComputed(function () {
                return numeral(_this.rewardValue()).format(_this.priceFormat);
            });
            this.reputationBonusText = ko.pureComputed(function () {
                var rewardValue = _this.rewardValue();
                if (rewardValue <= 25)
                    return 15;
                if (rewardValue <= 100)
                    return 30;
                return 50;
            });
            this.decreaseCustomRewardValue = function () {
                var val = _this.rewardValue() - _this.rewardStep;
                if (val >= _this.minReward) {
                    _this.rewardValue(val);
                }
            };
            this.increaseCustomRewardValue = function () {
                var val = _this.rewardValue() + _this.rewardStep;
                if (val <= _this.maxReward) {
                    _this.rewardValue(val);
                }
            };
            this.rewardTitleOptions = merchantUtils_1.default.getRewardTitleOptions();
            this.rewardTitleMaxLength = 45;
            this.rewardTitle = ko.observable("Отличная книга!").extend({
                required: {
                    onlyIf: function () {
                        return _this.stage() === "setRewardAmount" && _this.isCustomRewardValue();
                    }
                },
                minLengthLength: { params: 3, message: "Слишком короткое название" },
                maxLength: { params: this.rewardTitleMaxLength, message: "Название не может быть длиннее 45-ти символов" }
            });
            this.rewardTitleHint = ko.pureComputed(function () {
                var title = _this.rewardTitle() || "";
                var characters = title.length;
                return characters + "/" + _this.rewardTitleMaxLength;
            });
            this.priceWithReward = ko.pureComputed(function () {
                var mode = _this.mode();
                var reward = parseInt(_this.rewardValue());
                return mode === "reward" ? reward : _this.price + reward;
            });
            this.priceWithRewardText = ko.pureComputed(function () {
                return "" + numeral(_this.priceWithReward()).format(_this.priceFormat);
            });
            this.bankcardOptions = ko.observableArray();
            this.selectedBankCard = ko.observable();
            this.promoCode = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.stage() === "promoCode";
                    }
                }
            });
            this.showBuyModal = function (mode) {
                if (_this.disabled || !app.ensureAuth(true)) {
                    return;
                }
                _this.errorMessages([]);
                _this.mode(mode);
                if (mode === "reward") {
                    _this.stage("setRewardAmount");
                    _this.selectRandomRewardTitle();
                    _this.showModal({
                        title: "Подарить автору награду за книгу",
                        type: modalDialog_1.ModalType.Custom,
                        templateId: "buyWorkModal",
                        viewModel: _this,
                        maxWidth: "600px",
                        onSubmit: function () { }
                    });
                }
                else if (mode === "wallet") {
                    _this.stage("setBalanceAmount");
                    _this.workId = -1;
                    _this.workStatus = 1;
                    _this.workTitle = "Пополнение кошелька #" + _this.userId;
                    _this.allowDownloads = false;
                    _this.price = 0;
                    _this.discount(0);
                    _this.freezed = false;
                    _this.rewardsEnabled = false;
                    _this.coverUrl = "";
                    _this.visible = false;
                    _this.disabled = false;
                    _this.fb2FileMaxSize = 0;
                    _this.rewardTitle(null);
                    _this.rewardValue(_this.rewardOptions[1]);
                    if (_this.balanceAmount) {
                        _this.isCustomRewardValue(true);
                        _this.rewardValue(_this.balanceAmount);
                    }
                    _this.showModal({
                        title: "Пополнить кошелек",
                        type: modalDialog_1.ModalType.Custom,
                        templateId: "buyWorkModal",
                        viewModel: _this,
                        maxWidth: "600px",
                        onSubmit: function () { }
                    });
                }
                else if (mode === "gift") {
                    _this.stage("confirmBuyingGift");
                    _this.showModal({
                        title: "Покупка книги в подарок",
                        type: modalDialog_1.ModalType.Custom,
                        templateId: "buyWorkModal",
                        viewModel: _this,
                        maxWidth: "600px",
                        onSubmit: function () { }
                    });
                }
                else if (mode === "series") {
                    _this.stage("selectPaymentMethod");
                    _this.workId = -1;
                    _this.showModal({
                        title: "Покупка цикла",
                        type: modalDialog_1.ModalType.Custom,
                        templateId: "buyWorkModal",
                        viewModel: _this,
                        maxWidth: "600px",
                        onSubmit: function () { }
                    });
                }
                else {
                    _this.stage("startBuyingWork");
                    _this.selectRandomRewardTitle();
                    _this.showModal({
                        title: "Оплата доступа к книге",
                        type: modalDialog_1.ModalType.Custom,
                        templateId: "buyWorkModal",
                        viewModel: _this,
                        maxWidth: "600px",
                        onSubmit: function () { }
                    });
                }
            };
            this.checkSavedBankCards = function (el, payMethod) {
                _this.selectedPaymentMethod(payMethod);
                merchantUtils_1.default.checkSavedBankCards(el, payMethod, _this, app);
            };
            this.deleteSavedCard = function () {
                merchantUtils_1.default.deleteSavedCard(_this);
            };
            this.goToStage = function (stage, mode) {
                merchantUtils_1.default.goToStage(stage, mode, _this);
            };
            this.payMethodEnabled = function () {
                var payMethods = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    payMethods[_i - 0] = arguments[_i];
                }
                return merchantUtils_1.default.payMethodEnabled(_this, payMethods);
            };
            this.selectPayMethod = function (el, payMethod) {
                _this.selectedPaymentMethod(payMethod);
                merchantUtils_1.default.createOder(el, payMethod, _this, null);
            };
            this.selectReward = function (value) {
                merchantUtils_1.default.selectReward(value, _this);
            };
            this.previousRandomTitles = [];
            this.submitPromoCode = function () {
                merchantUtils_1.default.submitPromoCode(_this, function () { _this.modal.hide(); });
            };
            this.workId = params.workId;
            this.seriesId = params.seriesId;
            this.workStatus = params.workStatus;
            this.workTitle = JSON.parse("\"" + params.workTitle + "\"");
            this.allowDownloads = params.allowDownloads;
            this.price = params.price;
            this.discount(params.discount);
            this.freezed = params.freezed;
            this.rewardsEnabled = params.rewardsEnabled;
            this.coverUrl = params.coverUrl;
            this.visible = params.visible;
            this.disabled = params.disabled;
            this.fb2FileMaxSize = params.fb2FileMaxSize;
            this.saveCard = params.saveCard;
            this.userId = params.userId;
            this.balance = params.balance;
            this.balanceAmount = params.balanceAmount;
            this.paySelectionMin = params.paySelectionMin;
            this.paySelectionCommission = params.paySelectionCommission;
            this.giftsEnabled = params.giftsEnabled;
            this.isPurchased = params.isPurchased;
            this.cloudPaymentsCommission = params.cloudPaymentsCommission;
            this.cloudPaymentsMin = params.cloudPaymentsMin;
            this.payAnyWayCommission = params.payAnyWayCommission;
            this.payAnyWayMin = params.payAnyWayMin;
            this.robokassa2Commission = params.robokassa2Commission;
            if (params.discount) {
                var that = this;
                this.oldPrice = params.price;
                this.oldPriceText = numeral(this.oldPrice).format(this.priceFormat) + " \u20BD";
                this.discountText = this.discount() + "%";
                this.price = this.price - this.price * this.discount() / 100;
                var discountCountdown = $("#discountCountDown");
                var moreThan24Hours = moment(params.discountEnd).diff(moment(), "h") > 24;
                discountCountdown["countdown"](moment(params.discountEnd).toDate(), function (event) {
                    if (event.handleObj.type === "stop") {
                        that.price = that.oldPrice;
                        that.priceText(that.oldPrice);
                        that.discount(0);
                    }
                    else {
                        if (moreThan24Hours) {
                            $(this).html(event.strftime("%-D %!D:день,дня; %H:%M:%S"));
                        }
                        else {
                            $(this).html(event.strftime("%H:%M:%S"));
                        }
                    }
                });
            }
            if (params.rewardOptions)
                this.rewardOptions = params.rewardOptions;
            if (params.rewardStep)
                this.rewardStep = params.rewardStep;
            this.downloadText = "Доступно только чтение на сайте.";
            if (params.downloadText) {
                this.downloadText = params.downloadText;
            }
            if (params.disabledPayMethods)
                this.disabledPayMethods = params.disabledPayMethods;
            else
                this.disabledPayMethods = null;
            this.rewardValue.subscribe(function (newVal) {
                if (parseFloat(newVal) > _this.maxReward) {
                    _this.rewardValue(_this.maxReward);
                }
            });
            this.priceText(numeral(this.price).format(this.priceFormat));
            this.validation = ko.validatedObservable(this);
            merchantUtils_1.default.initButton(this);
        }
        BuyButtonComponent.prototype.selectRandomRewardTitle = function () {
            var index = _.random(0, this.rewardTitleOptions.length - 1);
            merchantUtils_1.default.selectRewardTitle(index, this);
        };
        return BuyButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("buy-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = BuyButtonComponent;
});

},{"../utils/merchantUtils":60,"./base/BaseComponent":5,"./modalDialog":20,"jquery":214,"jquery.countdown":189,"knockout":191,"lodash":216,"moment":219,"numeral":220}],8:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "toastr", "../viewModels/base/validatedViewModel", "../utils/ajaxUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var toastr = require("toastr");
    var validatedViewModel_1 = require("../viewModels/base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var modalDialog_1 = require("./modalDialog");
    var ChatRemoveButtonComponent = (function (_super) {
        __extends(ChatRemoveButtonComponent, _super);
        function ChatRemoveButtonComponent(params) {
            _super.call(this, params);
            this.userId = params.userId;
        }
        ChatRemoveButtonComponent.prototype.deleteChat = function () {
            var _this = this;
            this.init();
            setTimeout(function () {
                if (_this.validation === undefined) {
                    _this.initValidation();
                }
            }, 0);
            this.showModal({
                title: 'Требуется подтверждение',
                message: 'Вы уверены что хотите удалить диалог?',
                type: modalDialog_1.ModalType.ConfirmDelete,
                onSubmit: function () {
                    _this.modal.hide();
                    _this.init();
                    _this.processing(true);
                    ajaxUtils_1.AjaxUtils.post("pm/deleteChat", { userId: _this.userId })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            alert(result.messages[0]);
                            return;
                        }
                        toastr.success("Вы удалили диалог.");
                        ChatRemoveButtonComponent.reloadNotificationCount();
                        setTimeout(function () {
                            var url = window.location.pathname;
                            _this.redirectToPage(url);
                        }, 2000);
                    })
                        .always(function () {
                        _this.processing(false);
                    });
                }
            });
        };
        ChatRemoveButtonComponent.prototype.init = function () {
            this.errorMessages([]);
        };
        ChatRemoveButtonComponent.reloadNotificationCount = function () {
            var component = window["AppComponents"].Notifications;
            if (component) {
                component.reload();
            }
        };
        return ChatRemoveButtonComponent;
    }(validatedViewModel_1.default));
    ko.components.register("chat-remove-buttton", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ChatRemoveButtonComponent;
});

},{"../utils/ajaxUtils":45,"../viewModels/base/validatedViewModel":93,"./modalDialog":20,"knockout":191,"toastr":199}],9:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "lodash", "../utils/ajaxUtils", "../utils/dateTimeUtils", "./modalDialog", "../utils/imageZoomUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    // @ts-ignore
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var modalDialog_1 = require("./modalDialog");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var CommentFormV1Component = (function (_super) {
        __extends(CommentFormV1Component, _super);
        function CommentFormV1Component(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.$comments = $(".comments");
            this.$element = $(this.element);
            this.commentData = ko.observable();
            this._isTextChange = false;
            this.errorMessages = ko.observableArray([]);
            this.text = ko.observable("");
            this.mode = ko.observable();
            this.isIgnored = ko.observable();
            this.isPinned = ko.observable();
            this.canBePinned = ko.pureComputed(function () {
                var commentData = _this.commentData();
                return !commentData && _this.canPinned;
            });
            this.initialized = ko.observable(false);
            this.froalaOptions = {
                heightMin: 75,
                heightMax: 400,
                charCounterMax: 25000,
                initOnClick: true,
                placeholderText: "Написать комментарий...",
                pastePlain: true,
                charCounterCount: true,
                imageDefaultDisplay: "block",
                imageEditButtons: ["imageReplace", "imageAlign", "imageDisplay",
                    "imageAlt", "imageSize", "imageRemove"],
                imageDefaultAlign: "left",
                htmlAllowedTags: [
                    "a", "b", "blockquote", "br", "del", "div", "em", "embed", "i",
                    "iframe", "img", "p", "small", "span", "strike", "strong", "u"
                ],
                toolbarButtons: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "spoiler", "insertLink", "insertImage", "insertVideo",
                    "clearFormatting", "fullscreen"
                ],
                toolbarButtonsMD: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "spoiler", "insertLink", "insertImage", "insertVideo",
                    "clearFormatting", "fullscreen"
                ],
                toolbarButtonsSM: [
                    "bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage", "insertVideo", "fullscreen", "|", "undo", "redo"
                ],
                toolbarButtonsXS: [
                    "bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage", "insertVideo", "fullscreen", "|", "undo", "redo"
                ]
            };
            this.disableSubmit = ko.pureComputed(function () {
                var text = _this.text();
                var isEmpty = _.isEmpty(text);
                if (!isEmpty && !_this._isTextChange) {
                    _this.setDirtyText(true);
                }
                else if (isEmpty && _this._isTextChange) {
                    _this.setDirtyText(false);
                }
                return isEmpty;
            });
            this.submit = function () {
                if (_this.processing())
                    return;
                _this.processing(true);
                _this.errorMessages([]);
                var text = _this.text();
                var data = _.assign(_this.commentData() || {}, {
                    rootId: _this.rootId,
                    rootType: _this.rootType,
                    text: text,
                    isPinned: _this.isPinned()
                });
                ajaxUtils_1.AjaxUtils.post("comment/submit", data)
                    .done(function (result) {
                    if (result.isSuccessful) {
                        if (result.data.isPinned) {
                            $.pjax.reload("#pjax-container");
                            return;
                        }
                        _this.onSubmit(result.data);
                        _this.onSubmit = _this.defaultOnSubmit;
                        _this.initData();
                    }
                    else {
                        _this.errorMessages(result.messages);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            };
            this.rootId = params.rootId;
            this.rootType = params.rootType;
            this.canPinned = params.canPinned;
            this.onSubmit = this.defaultOnSubmit;
            this.initData();
            this.$element.find("textarea").on("froalaEditor.initialized", function (e, editor) {
                _this.initialized(true);
            });
        }
        CommentFormV1Component.prototype.showConfirmModal = function (submitFunc) {
            var _this = this;
            this.showModal({
                title: "Вы уверены?",
                message: "Комментарий не отправлен и не будет сохранён. Продолжить?",
                maxWidth: "400px",
                type: modalDialog_1.ModalType.Confirm,
                okBtnText: "Продолжить",
                onSubmit: function () {
                    submitFunc();
                    _this.modal.hide();
                }
            });
        };
        CommentFormV1Component.prototype.setDirtyText = function (value) {
            if (value === void 0) { value = true; }
            this._isTextChange = value;
        };
        CommentFormV1Component.prototype.startEditing = function (comment, onSubmit, onCancel, onDelete) {
            this.commentData(comment);
            this.onSubmit = onSubmit;
            this.onCancel = onCancel;
            this.onDelete = onDelete;
            this.resetState();
            this.mode("edit");
            this.isIgnored(comment.isIgnored);
            this.isPinned(comment.isPinned);
            $(".edit-reply textarea").froalaEditor("events.focus");
        };
        CommentFormV1Component.prototype.startCreating = function (comment, onSubmit) {
            this.commentData(comment);
            this.onSubmit = onSubmit;
            this.resetState();
            this.mode("new");
            this.isIgnored(comment.isIgnored);
            this.isPinned(comment.isPinned);
        };
        CommentFormV1Component.prototype.resetState = function () {
            var text = this.commentData() ? this.commentData().text : "";
            this.text(text);
            this.errorMessages([]);
        };
        CommentFormV1Component.prototype.cancel = function () {
            this.initData();
            this.onSubmit = this.defaultOnSubmit;
            if (this.onCancel) {
                this.onCancel();
            }
        };
        CommentFormV1Component.prototype.defaultOnSubmit = function (data) {
            var $html = $(data.html);
            this.$comments.prepend($html);
            dateTimeUtils_1.default.displayTime($html);
            imageZoomUtils_1.default.init($html);
        };
        CommentFormV1Component.prototype.remove = function () {
            var _this = this;
            if (this.processing())
                return;
            this.processing(true);
            this.errorMessages([]);
            ajaxUtils_1.AjaxUtils.post("comment/delete", { id: this.commentData().id })
                .done(function (result) {
                if (result.isSuccessful) {
                    _this.onDelete(result.data);
                    _this.initData();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        CommentFormV1Component.prototype.initData = function () {
            this.commentData(null);
            this.resetState();
            this.mode("new");
            this.isIgnored(false);
            this.isPinned(false);
        };
        Object.defineProperty(CommentFormV1Component.prototype, "isTextChange", {
            get: function () {
                return this._isTextChange;
            },
            enumerable: true,
            configurable: true
        });
        return CommentFormV1Component;
    }(baseComponent_1.default));
    ko.components.register("comment-form-v1", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CommentFormV1Component;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../utils/imageZoomUtils":57,"./base/baseComponent":6,"./modalDialog":20,"jquery":214,"knockout":191,"lodash":216}],10:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "bootstrap"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    require("bootstrap");
    /** Компонент для загрузки диалогового окна удаления пользователя */
    var DeleteUserFormComponent = (function (_super) {
        __extends(DeleteUserFormComponent, _super);
        function DeleteUserFormComponent() {
            _super.apply(this, arguments);
        }
        return DeleteUserFormComponent;
    }(baseComponent_1.default));
    exports.DeleteUserFormComponent = DeleteUserFormComponent;
    var componentName = "delete-user-form";
    if (!ko.components.isRegistered(componentName)) {
        ko.components.register(componentName, {});
    }
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = DeleteUserFormComponent;
});

},{"./base/baseComponent":6,"bootstrap":185,"knockout":191}],11:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var DisputedPostsComponent = (function (_super) {
        __extends(DisputedPostsComponent, _super);
        function DisputedPostsComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.items = ko.observableArray();
            var url;
            switch (params.type) {
                case "posts":
                    this.title = "<i class=\"icon-post\"></i> Последние комментарии";
                    url = "widget/disputedPosts";
                    break;
                case "works":
                    this.title = "<i class=\"icon-book2\"></i> Последние комментарии";
                    url = "widget/disputedWorks";
                    break;
                case "arts":
                    this.title = "<i class=\"icon-picture-o2\"></i> Последние комментарии";
                    url = "widget/disputedArts";
                    break;
                default:
                    console.error("Unsupported widget type.");
                    return;
            }
            ajaxUtils_1.AjaxUtils.get(url, {})
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.items(result.data);
            });
        }
        return DisputedPostsComponent;
    }(baseComponent_1.default));
    ko.components.register("disputed-items", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = DisputedPostsComponent;
});

},{"../utils/ajaxUtils":45,"./base/baseComponent":6,"knockout":191}],12:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "../utils/ajaxUtils", "../utils/imageUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var imageUtils_1 = require("../utils/imageUtils");
    var modalDialog_1 = require("./modalDialog");
    var EditAvatarComponent = (function (_super) {
        __extends(EditAvatarComponent, _super);
        function EditAvatarComponent(params, element, templateNodes) {
            _super.call(this, params, element, templateNodes);
            this.stage = ko.observable("uploadImage");
            this.fileType = "image/png";
            this.isLoading = ko.observable(false);
        }
        EditAvatarComponent.prototype.showEditModal = function () {
            var _this = this;
            this.errorMessages([]);
            this.stage("uploadImage");
            this.showModal({
                title: "Загрузка фотографии",
                type: modalDialog_1.ModalType.Custom,
                templateId: "editAvatarModal",
                viewModel: this,
                maxWidth: "580px",
                onShow: function ($modal) {
                    var $dropZone = $modal.find((".drop-zone"));
                    imageUtils_1.default.createDropZone($dropZone, function (files) {
                        _this.processFiles(files);
                    });
                    $modal.find("#editAvatarInput").on("change", function (e) {
                        _this.onSelectImage(e);
                    });
                }
            });
        };
        EditAvatarComponent.prototype.showConfirmDeleteModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление фотографии",
                message: "Вы уверены, что хотите удалить фотографию?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("account/deleteProfileImage", {})
                        .done(function (result) {
                        if (result.isSuccessful) {
                            _this.fullReloadPage();
                        }
                    });
                }
            });
        };
        EditAvatarComponent.prototype.selectImage = function () {
            var $input = this.modal.getModal().find("input[type='file']");
            $input.click();
        };
        EditAvatarComponent.prototype.onSelectImage = function (event) {
            this.errorMessages([]);
            var $input = $(event.target), files = event.target.files;
            this.processFiles(files);
            $input.val("");
        };
        EditAvatarComponent.prototype.processFiles = function (files) {
            var _this = this;
            if (files && files.length) {
                var file = files[0];
                if (file.size > 3145728) {
                    this.errorMessages(["Слишком большой размер файла. Пожалуйста, выберите файл размером не более 3 мб."]);
                    return;
                }
                if (!/^image\/\w+$/.test(file.type)) {
                    this.errorMessages(["Данный формат файла не поддерживается. Пожалуйста, выберите изображение."]);
                    return;
                }
                this.isLoading(true);
                this.stage("cropImage");
                var blobUrl = URL.createObjectURL(file);
                var windowWidth = $(window).width();
                var windowHeight = $(window).height();
                imageUtils_1.default.getImageSize(blobUrl).done(function (imageSize) {
                    if (imageSize.width < 150 || imageSize.height < 150) {
                        _this.errorMessages(["Слишком маленький размер фотографии."]);
                        _this.stage("uploadImage");
                        _this.isLoading(false);
                        return;
                    }
                    _this.fileType = file.type || _this.fileType;
                    var cropperSize = { width: Math.min(550, windowWidth - 70), height: Math.min(300, windowHeight - 70) };
                    var cropperAspectRatio = cropperSize.width / cropperSize.height;
                    var imageAspectRatio = imageSize.width / imageSize.height;
                    var scale = 1;
                    if (imageAspectRatio >= cropperAspectRatio) {
                        scale = cropperSize.height / imageSize.height;
                    }
                    else {
                        scale = cropperSize.width / imageSize.width;
                    }
                    var cropperWidth = _this.limit(scale * imageSize.width, 160, cropperSize.width);
                    var cropperHeight = _this.limit(scale * imageSize.height, 160, cropperSize.height);
                    var minCropBoxWidth = Math.max(cropperWidth, cropperHeight);
                    var minCropBoxHeight = minCropBoxWidth;
                    if (scale < 1) {
                        minCropBoxWidth = 160 * cropperSize.width / imageSize.width;
                        minCropBoxHeight = 160 * cropperSize.height / imageSize.height;
                    }
                    _this.$editAvatarImage = $(".edit-avatar-image");
                    _this.$editAvatarImage.cropper("destroy");
                    _this.$editAvatarImage.attr('src', blobUrl);
                    _this.$editAvatarImage.cropper({
                        aspectRatio: 1,
                        autoCropArea: 1,
                        viewMode: 1,
                        movable: false,
                        scalable: false,
                        zoomable: false,
                        doubleClickToggle: false,
                        minContainerWidth: cropperWidth,
                        minContainerHeight: cropperHeight,
                        minCropBoxWidth: minCropBoxWidth,
                        minCropBoxHeight: minCropBoxHeight,
                        preview: ".image-preview"
                    });
                    _this.$editAvatarImage
                        .one("built.cropper", function () {
                        try {
                            URL.revokeObjectURL(blobUrl); // Revoke when load complete
                            _this.isLoading(false);
                        }
                        catch (e) { }
                    });
                });
            }
        };
        EditAvatarComponent.prototype.backToUpload = function () {
            this.stage("uploadImage");
        };
        EditAvatarComponent.prototype.uploadImage = function (formElement) {
            var _this = this;
            setTimeout(function () {
                _this.processing(true);
                _this.errorMessages([]);
            }, 0);
            var dataUrl = this.$editAvatarImage.cropper("getCroppedCanvas")
                .toDataURL(this.fileType);
            ajaxUtils_1.AjaxUtils.post("account/updateAvatarImage", { "dataUrl": dataUrl })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                }
                else {
                    _this.fullReloadPage();
                }
            })
                .always(function () {
                setTimeout(function () {
                    _this.processing(false);
                }, 0);
            });
        };
        EditAvatarComponent.prototype.limit = function (value, min, max) {
            if (value < min)
                return min;
            if (value > max)
                return max;
            return value;
        };
        return EditAvatarComponent;
    }(baseComponent_1.default));
    ko.components.register("edit-avatar", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = EditAvatarComponent;
});

},{"../utils/ajaxUtils":45,"../utils/imageUtils":56,"./base/baseComponent":6,"./modalDialog":20,"jquery":214,"knockout":191}],13:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "./base/baseComponent", "../utils/ajaxUtils", "../utils/imageUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var baseComponent_1 = require("./base/baseComponent");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var imageUtils_1 = require("../utils/imageUtils");
    var modalDialog_1 = require("./modalDialog");
    var EditProfileBgComponent = (function (_super) {
        __extends(EditProfileBgComponent, _super);
        function EditProfileBgComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.imageUrl = ko.observable(this.params.url);
            this.status = this.params.status;
            this.fio = this.params.fio;
            this.isVerified = this.params.isVerified;
            this.profileUrl = this.params.profileUrl;
            this.isDefaultBg = this.params.isDefaultBg;
            this.bgImageUrl = ko.pureComputed(function () {
                return "url(" + _this.imageUrl() + ")";
            });
            this.editingBg = ko.observable(false);
            this.currentBgPosition = { x: 0, y: 0 };
            this.file = undefined;
            this.galleryUrl = undefined;
            this.galeryImages = ko.observableArray([]);
            this.choiseFromGalery = function (image) {
                _this.modal.hide();
                _this.imageUrl(image.url);
                _this.galleryUrl = image.url;
                _this.file = undefined;
                _this.editingBg(true);
                imageUtils_1.default.getImageSize(image.url).done(function (imageSize) {
                    _this.enableImageResize(imageSize);
                });
            };
            this.processFiles = function (files) {
                if (files && files.length) {
                    var file = files[0];
                    if (!/^image\/\w+$/.test(file.type)) {
                        _this.errorMessages(["Пожалуйста, выберите изображение."]);
                        return;
                    }
                    try {
                        URL.revokeObjectURL(_this.imageUrl());
                    }
                    catch (e) { }
                    var blobUrl_1 = URL.createObjectURL(file);
                    _this.file = file;
                    _this.galleryUrl = undefined;
                    imageUtils_1.default.getImageSize(blobUrl_1).done(function (imageSize) {
                        if (imageSize.width < 1140 || imageSize.height < 250) {
                            _this.errorMessages(["Слишком маленькое изображение. Пожалуйста, выберите изображение побольше."]);
                            return;
                        }
                        _this.modal.hide();
                        _this.imageUrl(blobUrl_1);
                        _this.editingBg(true);
                        setTimeout(function () {
                            _this.enableImageResize(imageSize);
                        }, 0);
                    });
                }
            };
            this.editingBg.subscribe(function (value) {
                if (value) {
                    $(".my-profile").addClass("editing-bg");
                }
                else {
                    $(".my-profile").removeClass("editing-bg");
                }
            });
        }
        EditProfileBgComponent.prototype.showEditModal = function () {
            var _this = this;
            this.showModal({
                title: "Фоновое изображение",
                templateId: "editProfileBgTemplate",
                type: modalDialog_1.ModalType.Custom,
                maxWidth: "700px",
                viewModel: this,
                onShow: function ($modal) {
                    var $dropZone = $modal.find((".drop-zone"));
                    imageUtils_1.default.createDropZone($dropZone, function (files) { return _this.processFiles(files); });
                    $modal.find("#editBgInput").on("change", function (e) {
                        _this.onSelectImage(e);
                    });
                    var imgGaleryRootUrl = window["app"].rootUrl + "dist/images/bgimages/";
                    _this.galeryImages([]);
                    for (var i = 1; i <= 38; i++) {
                        _this.galeryImages.push({
                            url: imgGaleryRootUrl + "full/" + i + ".jpg",
                            thumb: imgGaleryRootUrl + "thumbnails/" + i + ".jpg"
                        });
                    }
                    $($modal).find("a[data-toggle='tab']").on("show.bs.tab", function (e) {
                        if ($(e.target).attr("href") === "#gallery") {
                            $("#gallery").find("img").each(function (index, el) {
                                var $el = $(el);
                                $el.attr("src", $el.attr("lazy-src"));
                            });
                        }
                    });
                }
            });
        };
        EditProfileBgComponent.prototype.showConfirmDeleteModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление фонового изображения",
                message: "Вы уверены, что хотите удалить фоновое изображение?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("account/deleteProfileBgImage", {})
                        .done(function (result) {
                        if (result.isSuccessful) {
                            _this.fullReloadPage();
                        }
                    });
                }
            });
        };
        EditProfileBgComponent.prototype.selectImage = function () {
            var $input = this.modal.getModal().find("input[type='file']");
            $input.click();
        };
        EditProfileBgComponent.prototype.uploadImage = function (formElement) {
            var _this = this;
            setTimeout(function () {
                _this.processing(true);
                _this.errorMessages([]);
            }, 0);
            var formData = new FormData();
            if (this.file) {
                formData.append("file", this.file);
            }
            else if (this.galleryUrl) {
                formData.append("galleryUrl", this.galleryUrl);
            }
            formData.append("x", this.currentBgPosition.x);
            formData.append("y", this.currentBgPosition.y);
            this.currentAjaxRejuest = ajaxUtils_1.AjaxUtils.uploadFile("account/updateProfileBgImage", formData);
            this.currentAjaxRejuest.done(function (result) {
                if (!result.isSuccessful) {
                    alert("Произошла ошибка во время загрузки изображения. Попробуйте повторить загрузку через несколько минут.");
                }
                else {
                    _this.fullReloadPage();
                }
            }).always(function () {
                _this.currentAjaxRejuest = null;
                setTimeout(function () {
                    _this.processing(false);
                }, 0);
            });
        };
        EditProfileBgComponent.prototype.onSelectImage = function (event) {
            var files = event.target.files;
            this.processFiles(files);
            $(event.target).val("");
        };
        EditProfileBgComponent.prototype.cancelBgEditing = function () {
            try {
                URL.revokeObjectURL(this.imageUrl());
                if (this.currentAjaxRejuest) {
                    this.currentAjaxRejuest.abort();
                    this.currentAjaxRejuest = null;
                }
            }
            catch (e) { }
            this.imageUrl(this.params.url);
            this.editingBg(false);
            var $window = $(window), $cover = $(".cover");
            $window.off("mousemove touchmove");
            $window.off("mouseup touchend mouseleave");
            $cover.css("background-position", "0 0");
            $cover.off("mousedown touchstart");
            this.modal.hide();
        };
        EditProfileBgComponent.prototype.enableImageResize = function (imageSize) {
            var _this = this;
            var $cover = $(".editing-bg .cover"), $window = $(window);
            // Helper function to guarantee a value between low and hi unless bool is false
            var limit = function (low, hi, value) {
                if (value < low)
                    return low;
                if (value > hi)
                    return hi;
                return value;
            };
            var modifyEventForTouch = function (e) {
                e.clientX = e.originalEvent.touches[0].clientX;
                e.clientY = e.originalEvent.touches[0].clientY;
            };
            var imageDimensions = this.getImageDimensions(imageSize, $cover);
            $cover.on("mousedown touchstart", function (e) {
                if (e.target !== $cover[0]) {
                    return;
                }
                e.preventDefault();
                if (e.originalEvent["touches"]) {
                    modifyEventForTouch(e);
                }
                else if (e.which !== 1) {
                    return;
                }
                var x0 = e.clientX, y0 = e.clientY, pos = $cover.css("background-position").match(/(-?\d+).*?\s(-?\d+)/) || [], xPos = parseInt(pos[1]) || 0, yPos = parseInt(pos[2]) || 0;
                $window.on("mousemove touchmove", function (e) {
                    e.preventDefault();
                    if (e.originalEvent["touches"]) {
                        modifyEventForTouch(e);
                    }
                    var x = e.clientX, y = e.clientY;
                    xPos = limit($cover.innerWidth() - imageDimensions.width, 0, xPos + x - x0);
                    yPos = limit($cover.innerHeight() - imageDimensions.height + 1, 0, yPos + y - y0);
                    x0 = x;
                    y0 = y;
                    $cover.css("background-position", xPos + "px " + yPos + "px");
                    _this.currentBgPosition = {
                        x: xPos,
                        y: yPos
                    };
                });
                $window.on("mouseup touchend", function () {
                    $window.off("mousemove touchmove");
                    $window.off("mouseup touchend.dbg mouseleave");
                });
            });
        };
        EditProfileBgComponent.prototype.getImageDimensions = function (imageSize, $container) {
            var imageDimensions = { width: imageSize.width, height: imageSize.height };
            var elementWidth = $container.innerWidth(), elementHeight = $container.innerHeight(), elementAspectRatio = elementWidth / elementHeight, imageAspectRatio = imageSize.width / imageSize.height;
            var scale;
            if (imageAspectRatio >= elementAspectRatio) {
                scale = elementHeight / imageSize.height;
            }
            else {
                scale = elementWidth / imageSize.width;
            }
            imageDimensions.width = imageSize.width * scale;
            imageDimensions.height = imageSize.height * scale;
            return imageDimensions;
        };
        return EditProfileBgComponent;
    }(baseComponent_1.default));
    ko.components.register("edit-profile-bg", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = EditProfileBgComponent;
});

},{"../utils/ajaxUtils":45,"../utils/imageUtils":56,"./base/baseComponent":6,"./modalDialog":20,"jquery":214,"knockout":191}],14:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "../viewModels/base/validatedViewModel", "../utils/ajaxUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("../viewModels/base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var modalDialog_1 = require("./modalDialog");
    var TargetType;
    (function (TargetType) {
        TargetType[TargetType["User"] = 0] = "User";
        TargetType[TargetType["Work"] = 1] = "Work";
        TargetType[TargetType["Post"] = 2] = "Post";
        TargetType[TargetType["Review"] = 3] = "Review";
        TargetType[TargetType["Comment"] = 4] = "Comment";
        TargetType[TargetType["Collection"] = 5] = "Collection";
        TargetType[TargetType["Art"] = 6] = "Art";
    })(TargetType || (TargetType = {}));
    var FeedbackFormComponent = (function (_super) {
        __extends(FeedbackFormComponent, _super);
        function FeedbackFormComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params);
            this.commentMaxLength = 1000;
            this.targetId = ko.observable();
            this.targetType = ko.observable();
            this.targetTypeAsString = ko.pureComputed(function () {
                return TargetType[_this.targetType()];
            });
            this.url = ko.observable();
            this.title = ko.pureComputed(function () {
                var title = "Жалоба на ";
                switch (_this.targetType()) {
                    case TargetType.User:
                        title += "пользователя";
                        break;
                    case TargetType.Work:
                        title += "произведение";
                        break;
                    case TargetType.Post:
                        title += "запись в блоге";
                        break;
                    case TargetType.Review:
                        title += "рецензию";
                        break;
                    case TargetType.Comment:
                        title += "комментарий";
                        break;
                    case TargetType.Collection:
                        title += "подборку";
                        break;
                    case TargetType.Art:
                        title += "иллюстрацию";
                        break;
                }
                return title;
            });
            this.comment = ko.observable("");
            this.commentHint = ko.pureComputed(function () {
                var comment = _this.comment() || "";
                return comment.length + "/" + _this.commentMaxLength;
            });
            this.categories = ko.pureComputed(function () {
                var result = [];
                switch (_this.targetType()) {
                    case TargetType.User:
                        result = [
                            "Нарушение правил",
                            "Оскорбление",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                    case TargetType.Comment:
                        result = [
                            "Нарушение правил",
                            "Оскорбление",
                            "Провокация конфликта",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                    case TargetType.Post:
                        result = [
                            "Нарушение правил",
                            "Неправильная тема",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                    case TargetType.Review:
                    case TargetType.Collection:
                        result = [
                            "Нарушение правил",
                            "Неправильные тэги",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                    case TargetType.Work:
                        result = [
                            "Неправильный жанр (укажите какой именно)",
                            "Книга продается по подписке и давно не обновлялась автором",
                            'Произведение не соответствует статусу ("полный текст", "в процессе", "ознакомительный фрагмент")',
                            "Нарушение авторского права",
                            "Материал для взрослых (18+)",
                            "Нарушение правил сайта",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                    case TargetType.Art:
                        result = [
                            "Нарушение авторского права",
                            "Материал для взрослых (18+)",
                            "Нарушение правил сайта",
                            "Спам",
                            "Остальное"
                        ];
                        break;
                }
                return result;
            });
            this.selectedCategory = ko.observable().extend({
                required: {
                    value: true,
                    message: "Пожалуйста, укажите причину жалобы"
                }
            });
        }
        FeedbackFormComponent.prototype.show = function (targetId, targetType, url) {
            var _this = this;
            this.errorMessages([]);
            this.targetId(targetId);
            this.targetType(TargetType[targetType]);
            this.url(url);
            if (this.comment()) {
                this.comment(null);
            }
            if (this.selectedCategory()) {
                this.selectedCategory(null);
            }
            setTimeout(function () {
                if (_this.validation === undefined) {
                    _this.initValidation();
                }
            }, 0);
            if (!app.ensureAuth()) {
                return;
            }
            this.showModal({
                title: this.title(),
                type: modalDialog_1.ModalType.Custom,
                templateId: "feedBackFormModal",
                maxWidth: "435px",
                viewModel: this
            });
        };
        FeedbackFormComponent.prototype.submit = function () {
            var _this = this;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            ;
            if (this.processing())
                return;
            this.processing(true);
            this.errorMessages([]);
            var data = {
                targetId: this.targetId(),
                targetType: this.targetTypeAsString(),
                url: this.url(),
                category: this.selectedCategory(),
                comment: this.comment()
            };
            ajaxUtils_1.AjaxUtils.post("feedback/complaint", data)
                .done(function (result) {
                if (result.isSuccessful) {
                    _this.showModal({
                        title: _this.title(),
                        type: modalDialog_1.ModalType.Success,
                        message: "Спасибо за то, что помогаете делать наш сервис еще лучше!",
                        maxWidth: "435px"
                    });
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return FeedbackFormComponent;
    }(validatedViewModel_1.default));
    ko.components.register("feedback-form", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = FeedbackFormComponent;
});

},{"../utils/ajaxUtils":45,"../viewModels/base/validatedViewModel":93,"./modalDialog":20,"knockout":191}],15:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "./modalDialog", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var modalDialog_1 = require("./modalDialog");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var HideButtonComponent = (function (_super) {
        __extends(HideButtonComponent, _super);
        function HideButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.isDisliked = ko.observable(false);
            this.isSeriesHidden = ko.observable(false);
            this.hiddenAuthorIds = ko.observableArray([]);
            this.isHidden = ko.observable(false);
            this.getHideOptions = ko.pureComputed(function () {
                var hideOptions = [];
                var isHidden = false;
                if (_this.workId) {
                    if (_this.isDisliked()) {
                        hideOptions.push({ command: "Hide", text: "Скрывать произведение", icon: "icon-book", checked: true });
                        isHidden = true;
                    }
                    else {
                        hideOptions.push({ command: "Hide", text: "Скрыть произведение", icon: "icon-book", checked: false });
                    }
                }
                if (_this.seriesId) {
                    if (_this.isSeriesHidden()) {
                        hideOptions.push({ command: "Series", text: "Скрывать произведения цикла «" + _this.seriesTitle + "»", icon: "icon-2-books-stack", checked: true });
                        isHidden = true;
                    }
                    else {
                        hideOptions.push({ command: "Series", text: "Скрыть произведения цикла «" + _this.seriesTitle + "»", icon: "icon-2-books-stack", checked: false });
                    }
                }
                if (_this.authors) {
                    for (var authorId in _this.authors) {
                        var hiddenAuthorIds = _this.hiddenAuthorIds();
                        if (hiddenAuthorIds && hiddenAuthorIds.indexOf(parseInt(authorId)) != -1) {
                            hideOptions.push({ command: "Author", authorId: authorId, text: "Скрывать произведения автора <b>" + _this.authors[authorId] + "</b>", icon: "icon-user", checked: true });
                            isHidden = true;
                        }
                        else {
                            hideOptions.push({ command: "Author", authorId: authorId, text: "Скрыть произведения автора <b>" + _this.authors[authorId] + "</b>", icon: "icon-user", checked: false });
                        }
                    }
                }
                _this.isHidden(isHidden);
                return hideOptions;
            });
            this.showHelp = function () {
                _this.showModal({
                    title: "Как работает скрытие?",
                    type: modalDialog_1.ModalType.Custom,
                    templateId: "hideButtonHelp",
                    maxWidth: "600px"
                });
            };
            this.updateHidden = function (args) {
                if (!app.ensureAuth()) {
                    return;
                }
                // Режим переключателя единственной сущности
                if (_this.displayMode) {
                    args = {
                        checked: _this.isHidden()
                    };
                    if (_this.workId) {
                        args.command = "Hide";
                    }
                    else if (_this.seriesId) {
                        args.command = "Series";
                    }
                    else if (_this.authors) {
                        args.command = "Author";
                        args.authorId = Object.keys(_this.authors)[0];
                    }
                    else
                        return;
                }
                var libraryButton = _this.workId ? window["AppComponents"].LibraryButton : null;
                var libraryState = libraryButton ? libraryButton.currentState() : "";
                var params = {
                    url: "",
                    data: {}
                };
                if (_this.processing())
                    return;
                _this.processing(true);
                if (libraryButton)
                    libraryButton.processing(true);
                if (args.command === "Hide") {
                    libraryState = args.checked ? "None" : "Disliked";
                    params.url = "work/updateLibrary";
                    params.data = {
                        ids: [_this.workId],
                        state: libraryState
                    };
                }
                else if (args.command === "Series") {
                    params.url = "hide/series";
                    params.data = {
                        id: _this.seriesId,
                        deleted: args.checked
                    };
                }
                else if (args.command === "Author") {
                    params.url = "hide/author";
                    params.data = {
                        id: args.authorId,
                        deleted: args.checked
                    };
                }
                else
                    return;
                ajaxUtils_1.AjaxUtils.post(params.url, params.data).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    else {
                        if (args.command === "Hide") {
                            _this.isDisliked(!args.checked);
                            if (libraryButton)
                                libraryButton.currentState(libraryState);
                        }
                        else if (args.command === "Series") {
                            _this.isSeriesHidden(!args.checked);
                        }
                        else if (args.command === "Author") {
                            var authorId = parseInt(args.authorId);
                            var arr = _this.hiddenAuthorIds();
                            var index = arr.indexOf(authorId, 0);
                            if (index > -1) {
                                arr.splice(index, 1);
                            }
                            if (!args.checked)
                                arr.push(authorId);
                            _this.hiddenAuthorIds(arr);
                        }
                        if (_this.displayMode)
                            _this.getHideOptions();
                    }
                }).always(function () {
                    _this.processing(false);
                    if (libraryButton)
                        libraryButton.processing(false);
                });
            };
            this.workId = params.workId;
            this.leftMenu = params.leftMenu === true;
            this.displayMode = params.displayMode ? params.displayMode : null;
            this.isHidden(false);
            this.isDisliked(params.isDisliked === true);
            this.isSeriesHidden(params.isSeriesHidden === true);
            this.seriesId = params.seriesId;
            this.seriesTitle = params.seriesTitle;
            if (params.hiddenAuthorIds)
                this.hiddenAuthorIds(params.hiddenAuthorIds);
            this.authors = params.authors;
            if (this.displayMode)
                this.getHideOptions();
        }
        return HideButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("hide-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = HideButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/BaseComponent":5,"./modalDialog":20,"knockout":191}],16:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "toastr", "../viewModels/base/validatedViewModel", "../utils/ajaxUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var toastr = require("toastr");
    var validatedViewModel_1 = require("../viewModels/base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var modalDialog_1 = require("./modalDialog");
    var IgnoreListButtonComponent = (function (_super) {
        __extends(IgnoreListButtonComponent, _super);
        function IgnoreListButtonComponent(params, element, templateNodes) {
            _super.call(this, params);
            this.commentMaxLength = 500;
            this.ignored = ko.observable();
            this.userId = params.userId;
            this.fio = params.fio;
            if (ko.isWriteableObservable(params.ignored)) {
                this.ignored = params.ignored;
            }
            else {
                this.ignored(params.ignored);
            }
        }
        IgnoreListButtonComponent.prototype.confirm = function () {
            var _this = this;
            this.errorMessages([]);
            setTimeout(function () {
                if (_this.validation === undefined) {
                    _this.initValidation();
                }
            }, 0);
            this.showModal({
                title: "Добавить в игнор-лист",
                type: modalDialog_1.ModalType.Custom,
                templateId: "ignoreListModal",
                maxWidth: "500px",
                viewModel: this
            });
        };
        IgnoreListButtonComponent.prototype.submit = function () {
            var _this = this;
            this.processing(true);
            this.errorMessages([]);
            ajaxUtils_1.AjaxUtils.post("ignoreList/add", { userId: this.userId })
                .done(function (result) {
                if (result.isSuccessful) {
                    toastr.success("Вы добавили пользователя в игнор-лист.");
                    _this.ignored(true);
                    _this.modal.hide();
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        IgnoreListButtonComponent.prototype.remove = function () {
            var _this = this;
            this.processing(true);
            this.errorMessages([]);
            ajaxUtils_1.AjaxUtils.post("ignoreList/remove", { userId: this.userId })
                .done(function (result) {
                if (result.isSuccessful) {
                    toastr.success("Вы убрали пользователя из игнор-листа.");
                    _this.ignored(false);
                    _this.reloadPage();
                }
                else {
                    alert(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return IgnoreListButtonComponent;
    }(validatedViewModel_1.default));
    ko.components.register("ignore-list-buttton", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = IgnoreListButtonComponent;
});

},{"../utils/ajaxUtils":45,"../viewModels/base/validatedViewModel":93,"./modalDialog":20,"knockout":191,"toastr":199}],17:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "lodash", "../utils/ajaxUtils", "../utils/metrikaUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var _ = require("lodash");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var metrikaUtils_1 = require("../utils/metrikaUtils");
    var LibraryButtonComponent = (function (_super) {
        __extends(LibraryButtonComponent, _super);
        function LibraryButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.currentState = ko.observable("None");
            this.stateForDropdown = ko.pureComputed(function () {
                var currentState = _this.currentState();
                if (currentState === "None") {
                    return { title: "В библиотеку", icon: "icon-plus" };
                }
                return _this.getStateInfo(currentState);
            });
            this.statesToUpdate = ko.pureComputed(function () {
                var currentState = _this.currentState();
                return _.filter(_this.libraryStates, function (s) {
                    return s.state !== currentState;
                });
            });
            this.getStateInfo = function (state) {
                return _.find(_this.libraryStates, function (s) {
                    return s.state === state;
                });
            };
            this.updateLibrary = function (stateInfo) {
                if (!app.ensureAuth()) {
                    return;
                }
                var hideButton = window["AppComponents"].HideButton;
                if (_this.processing())
                    return;
                _this.processing(true);
                if (hideButton)
                    hideButton.processing(true);
                var state = stateInfo.state;
                if (state !== "None" && state !== "Disliked") {
                    try {
                        metrikaUtils_1.default.reachGoal("addToLibrary", { workId: _this.workId, state: state });
                    }
                    catch (ex) { }
                }
                ajaxUtils_1.AjaxUtils.post("work/updateLibrary", {
                    ids: [_this.workId],
                    state: state
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    else {
                        _this.currentState(state);
                        if (hideButton)
                            hideButton.isDisliked(state == "Disliked");
                    }
                }).always(function () {
                    _this.processing(false);
                    if (hideButton)
                        hideButton.processing(false);
                });
            };
            if (params.format === "EBook") {
                this.libraryStates = [
                    { state: "Reading", title: "Читаю", icon: "icon-2-library-reading" },
                    { state: "Saved", title: "Отложено на потом", icon: "icon-2-clock" },
                    { state: "Finished", title: "Прочитано", icon: "icon-2-library-finished" }];
            }
            else if (params.format === "Audiobook") {
                this.libraryStates = [
                    { state: "Reading", title: "Слушаю", icon: "icon-2-player-play" },
                    { state: "Saved", title: "Отложено на потом", icon: "icon-2-clock" },
                    { state: "Finished", title: "Прослушано", icon: "icon-2-library-finished" }];
            }
            (_a = this.libraryStates).push.apply(_a, [
                { state: "Disliked", title: "Не интересно", icon: "icon-eye-slash" },
                { state: "None", title: "Удалить из библиотеки", icon: "icon-cross text-danger" }
            ]);
            this.currentState(params.state);
            this.workId = params.workId;
            this.inlineBtn = params.inlineBtn;
            this.onlyIcon = params.onlyIcon;
            this.leftMenu = params.leftMenu;
            var _a;
        }
        return LibraryButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("library-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = LibraryButtonComponent;
});

},{"../utils/ajaxUtils":45,"../utils/metrikaUtils":61,"./base/BaseComponent":5,"knockout":191,"lodash":216}],18:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "numeral", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var LikeButtonComponent = (function (_super) {
        __extends(LikeButtonComponent, _super);
        function LikeButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.voteId = ko.observable();
            this.numeral = numeral;
            this.isLiked = ko.pureComputed(function () {
                return !!_this.voteId();
            });
            this.likeCount = ko.observable();
            this.targetId = params.targetId;
            this.type = params.type;
            this.disabled = params.disabled;
            this.voteId(params.voteId);
            this.likeCount(params.likeCount);
            var $siblings = $(element).siblings();
            this.$btn = $siblings.filter(".btn-like");
            this.$heart = $siblings.find(".heart");
            this.$heartContainer = $siblings.find(".heart-container");
        }
        LikeButtonComponent.prototype.toggleLike = function () {
            var _this = this;
            if (this.disabled)
                return;
            if (this.$btn.attr("disabled"))
                return;
            this.$btn.attr("disabled", "disabled");
            if (this.isLiked()) {
                this.$heart.removeClass("heart-animation");
                this.$btn.addClass("hover-state-canceled");
                this.$btn.on("mouseleave", function () {
                    _this.$btn.removeClass("hover-state-canceled");
                    _this.$btn.off("mouseleave");
                });
            }
            else {
                this.$heartContainer.css({ overflow: "visible" });
                this.$btn.removeClass("hover-state-canceled");
                this.$heart.addClass("heart-animation");
                setTimeout(function () {
                    _this.$heartContainer.css({ overflow: "hidden" });
                }, 800);
            }
            var url = "";
            switch (this.type) {
                case "Work":
                    url = "work/like";
                    break;
                case "Art":
                    url = "art/like";
                    break;
                case "Collection":
                    url = "collection/like";
                    break;
                default:
                    alert("LikeButton error. Unknown type.");
                    break;
            }
            ajaxUtils_1.AjaxUtils.post(url, {
                targetId: this.targetId,
                isLiked: !this.isLiked(),
                voteId: this.voteId()
            }).done(function (result) {
                if (result.isSuccessful) {
                    _this.voteId(result.data.voteId);
                    _this.likeCount(result.data.likeCount);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.$btn.removeAttr("disabled");
            });
        };
        return LikeButtonComponent;
    }(baseComponent_1.default));
    ko.components.register("like-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = LikeButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/baseComponent":6,"jquery":214,"knockout":191,"numeral":220}],19:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "lodash", "drop", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var Drop = require("drop");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var MarkButtonComponent = (function (_super) {
        __extends(MarkButtonComponent, _super);
        function MarkButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.defaultBtnTitle = "Реакции";
            this.workMarks = ko.observableArray();
            this.isDisabled = ko.observable(false);
            this.disabledBtnTitle = ko.observable();
            this.activeMark = ko.pureComputed(function () {
                return _.find(_this.allMarks, function (m) { return m.enumValue === _this.workMarks()[0]; });
            });
            this.titleBtn = ko.pureComputed(function () {
                if (_this.activeMark()) {
                    return _this.activeMark().title;
                }
                else {
                    return _this.defaultBtnTitle;
                }
            });
            this.activeMarkSrc = ko.pureComputed(function () {
                if (_this.activeMark()) {
                    return app.rootUrl + "distCommon/emoji/" + _this.activeMark().code + ".svg";
                }
                else {
                    return "";
                }
            });
            this.activeMarkAlt = ko.pureComputed(function () {
                if (_this.activeMark()) {
                    return "&#x" + _this.activeMark().code;
                }
                else {
                    return "";
                }
            });
            this.isLoading = ko.observable(false);
            this.toggleMark = function (mark) {
                if (_this.isLoading())
                    return;
                _this.isLoading(true);
                var isActive = _this.workMarks().indexOf(mark) === -1;
                ajaxUtils_1.AjaxUtils.post("work/mark", {
                    workId: _this.workId,
                    isActive: isActive,
                    mark: mark
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.workMarks(result.data.marks);
                }).always(function () {
                    _this.isLoading(false);
                });
            };
            this.workId = params.workId;
            this.allMarks = params.allMarks;
            this.workMarks(params.workMarks || []);
            this.isDisabled(params.disabled || false);
            this.disabledBtnTitle(params.disabledBtnTitle);
            var marksDropdowm = document.getElementById("marks-dropdown");
            if (marksDropdowm && !this.isDisabled()) {
                var marksTemplateMarkup = marksDropdowm.innerHTML;
                this.initDropdown($(element), marksTemplateMarkup, function ($content) {
                    $content.find(".work-mark-button img")
                        .on("mouseover", function (e) {
                        var $img = $(e.target);
                        $img.attr("src", $img.attr("data-animated-src"));
                    })
                        .on("mouseout", function (e) {
                        var $img = $(e.target);
                        $img.attr("src", $img.attr("data-src"));
                    });
                });
            }
        }
        MarkButtonComponent.prototype.initDropdown = function ($btn, template, postProcessFunc) {
            var _this = this;
            if (postProcessFunc === void 0) { postProcessFunc = null; }
            var drop = new Drop({
                target: $btn[0],
                content: function () {
                    var $content = $("<div />").html(template);
                    ko.applyBindingsToDescendants(_this, $content[0]);
                    if (postProcessFunc) {
                        setTimeout(function () {
                            postProcessFunc($content);
                        }, 100);
                    }
                    return $content[0];
                },
                /*openOn: "hover",*/
                hoverCloseDelay: 150,
                constrainToScrollParent: true,
                tetherOptions: {
                    attachment: "top center",
                    targetAttachment: "bottom center",
                    constraints: [
                        {
                            to: "window",
                            attachment: "together",
                            pin: true
                        }
                    ]
                }
            });
            $btn.addClass("btn-tether-drop");
            drop.on("open", function () {
                drop.position();
                $btn.addClass("open");
            });
            drop.on("close", function () {
                $btn.removeClass("open");
            });
            $btn.data("drop", drop);
        };
        return MarkButtonComponent;
    }(baseComponent_1.default));
    ko.components.register("mark-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = MarkButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/baseComponent":6,"drop":197,"jquery":214,"knockout":191,"lodash":216}],20:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "lodash", "bootstrap"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    require("bootstrap");
    (function (ModalType) {
        ModalType[ModalType["Custom"] = 0] = "Custom";
        ModalType[ModalType["ConfirmDelete"] = 1] = "ConfirmDelete";
        ModalType[ModalType["Confirm"] = 2] = "Confirm";
        ModalType[ModalType["Alert"] = 3] = "Alert";
        ModalType[ModalType["Success"] = 4] = "Success";
        ModalType[ModalType["Error"] = 5] = "Error";
        ModalType[ModalType["ConfirmDeleteWithoutUndone"] = 6] = "ConfirmDeleteWithoutUndone";
        ModalType[ModalType["ReverseConfirm"] = 7] = "ReverseConfirm";
    })(exports.ModalType || (exports.ModalType = {}));
    var ModalType = exports.ModalType;
    var defaultOptions = {
        width: "600px",
        type: ModalType.ConfirmDelete,
        okBtnText: "OK",
        deleteBtnText: "Удалить"
    };
    var ModalDialogComponent = (function (_super) {
        __extends(ModalDialogComponent, _super);
        function ModalDialogComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.title = ko.observable();
            this.message = ko.observable();
            this.minWidth = ko.observable();
            this.maxWidth = ko.observable();
            this.type = ko.observable();
            this.deleteBtnText = ko.observable();
            this.okBtnText = ko.observable();
            this.templateId = ko.observable();
            this.isVisible = ko.observable(false);
            this.templateData = ko.observable();
            this.deleteWithoutUndoneText = ko.observable();
            this.deleteWithoutUndoneBtnDisabled = ko.pureComputed(function () {
                var text = _this.deleteWithoutUndoneText() || "";
                return text.toUpperCase() !== "УДАЛИТЬ";
            });
            var $el = $(element);
            if ($el.parent()[0] !== document.body) {
                $el.appendTo(document.body);
            }
            this.$modal = $el.find(".modal");
            var modalOptions = _.defaults({}, params.modal, {
                backdrop: true,
                show: false
            });
            this.$modal.modal(modalOptions);
        }
        ModalDialogComponent.prototype.show = function (modalOptions) {
            var _this = this;
            var options = _.defaults(modalOptions, defaultOptions);
            this.title(options.title);
            this.minWidth(options.minWidth);
            if (options.maxWidth) {
                var width = parseInt(options.maxWidth.substring(0, options.maxWidth.indexOf("px")));
                var maxWidth = $(window).width() - 40;
                if (width > maxWidth) {
                    options.maxWidth = maxWidth + "px";
                }
            }
            this.maxWidth(options.maxWidth);
            this.deleteBtnText(options.deleteBtnText);
            this.okBtnText(options.okBtnText);
            this.type(options.type);
            if (this.type() === ModalType.Custom) {
                if (_.isEmpty(options.templateId)) {
                    throw new Error("\"CustomMarkup\" property should be specified.");
                }
                if (!(document.getElementById(options.templateId))) {
                    throw new Error("Template " + options.templateId + " not found");
                }
                if (options.viewModel === undefined) {
                    options.viewModel = window["app"].viewModel;
                }
                this.templateData(options.viewModel);
                this.templateId(options.templateId);
            }
            else {
                if (_.isEmpty(options.message)) {
                    throw new Error("\"Message\" property should be specified.");
                }
                this.message(options.message);
                this.onSubmit = options.onSubmit;
            }
            this.errorMessages([]);
            this.$modal.modal("show");
            this.isVisible(true);
            this.$modal.on("hide.bs.modal", function () {
                _this.isVisible(false);
                if (options.onHide) {
                    options.onHide(_this.getModal());
                }
            });
            if (options.onShow) {
                setTimeout(function () {
                    options.onShow(_this.getModal());
                });
            }
        };
        ModalDialogComponent.prototype.toggleProcessing = function (isProcessing) {
            this.processing(isProcessing);
        };
        ModalDialogComponent.prototype.showErrorMessage = function (messages) {
            this.errorMessages(messages);
        };
        ModalDialogComponent.prototype.submitBtnClick = function () {
            var _this = this;
            this.toggleProcessing(true);
            try {
                var result = this.onSubmit();
                if (result && result["done"]) {
                    result.done(function (result) {
                        if (result) {
                            if (result.isSuccessful) {
                                _this.hide();
                            }
                            else {
                                _this.errorMessages(result.messages);
                            }
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                }
                else {
                    this.processing(false);
                }
            }
            catch (ex) {
                this.errorMessages(["Упс, произошла ошибка. Сообщите, пожалуйста, в тех. поддержку."]);
                console.error(ex.toString());
                this.processing(false);
            }
        };
        ModalDialogComponent.prototype.hide = function () {
            this.$modal.modal("hide");
        };
        ModalDialogComponent.prototype.getModal = function () {
            return this.$modal;
        };
        return ModalDialogComponent;
    }(baseComponent_1.default));
    exports.ModalDialogComponent = ModalDialogComponent;
    var componentName = "modal-dialog";
    if (!ko.components.isRegistered(componentName)) {
        ko.components.register(componentName, {});
    }
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ModalDialogComponent;
});

},{"./base/baseComponent":6,"bootstrap":185,"jquery":214,"knockout":191,"lodash":216}],21:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "../viewModels/base/validatedViewModel", "../utils/ajaxUtils", "../utils/dateTimeUtils", "./modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var validatedViewModel_1 = require("../viewModels/base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var modalDialog_1 = require("./modalDialog");
    var ModerateCommentComponent = (function (_super) {
        __extends(ModerateCommentComponent, _super);
        function ModerateCommentComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params);
            this.commentMaxLength = 500;
            this.targetId = ko.observable();
            this.isModerator = ko.observable(false);
            this.removalReasonComment = ko.observable("");
            this.removalReasonCommentHint = ko.pureComputed(function () {
                var comment = _this.removalReasonComment() || "";
                return comment.length + "/" + _this.commentMaxLength;
            });
            this.removeAndHide = ko.observable("");
            this.removalReasons = [
                "Оскорбление пользователя",
                "Провокация конфликта",
                "Спам",
                "Нарушение правил",
                "Остальное"
            ];
            this.selectedReason = ko.observable().extend({
                required: {
                    params: true,
                    message: "Пожалуйста, укажите причину удаления."
                }
            });
        }
        ModerateCommentComponent.prototype.showEdit = function (commentId, selectedReason, removalReason) {
            var _this = this;
            this.errorMessages([]);
            this.targetId(commentId);
            this.isModerator(true);
            this.selectedReason(selectedReason);
            this.removalReasonComment(removalReason);
            setTimeout(function () {
                if (_this.validation === undefined) {
                    _this.initValidation();
                }
            }, 0);
            this.showModal({
                title: "Редактирование причины удаления комментария",
                type: modalDialog_1.ModalType.Custom,
                templateId: "moderateCommentFormModal",
                maxWidth: "435px",
                viewModel: this
            });
        };
        ModerateCommentComponent.prototype.show = function (commentId, isModerator) {
            var _this = this;
            this.errorMessages([]);
            this.targetId(commentId);
            this.isModerator(isModerator);
            if (this.selectedReason()) {
                this.selectedReason(null);
            }
            if (this.removalReasonComment()) {
                this.removalReasonComment("");
            }
            setTimeout(function () {
                if (_this.validation === undefined) {
                    _this.initValidation();
                }
            }, 0);
            this.showModal({
                title: "Удаление комментария",
                type: modalDialog_1.ModalType.Custom,
                templateId: "moderateCommentFormModal",
                maxWidth: "435px",
                viewModel: this
            });
        };
        ModerateCommentComponent.prototype.submit = function () {
            var _this = this;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            this.processing(true);
            this.errorMessages([]);
            var data = {
                id: this.targetId(),
                removalReason: this.selectedReason(),
                removalReasonComment: this.removalReasonComment(),
                removeAndHide: this.removeAndHide()
            };
            ajaxUtils_1.AjaxUtils.post("comment/delete", data)
                .done(function (result) {
                if (result.isSuccessful) {
                    if (result.data.isReload) {
                        ModerateCommentComponent.reloadComments();
                    }
                    else {
                        var commentId = "#comment_" + _this.targetId();
                        var $target = $(commentId);
                        var $html = $(result.data.html);
                        if (_this.removeAndHide()) {
                            var repliesComment = $target.siblings(".comment, .comment-toggle, .replies");
                            repliesComment.replaceWith($html);
                        }
                        else {
                            var $comment = $target.siblings(".comment");
                            $comment.replaceWith($html);
                        }
                        dateTimeUtils_1.default.displayTime($html);
                    }
                    _this.modal.hide();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ModerateCommentComponent.reloadComments = function () {
            $.pjax.reload("#pjax-container");
        };
        return ModerateCommentComponent;
    }(validatedViewModel_1.default));
    ko.components.register("moderate-comment-form", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ModerateCommentComponent;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../viewModels/base/validatedViewModel":93,"./modalDialog":20,"jquery":214,"knockout":191}],22:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "../utils/commentLoadUtil", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var commentLoadUtil_1 = require("../utils/commentLoadUtil");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var NotificationsComponent = (function (_super) {
        __extends(NotificationsComponent, _super);
        function NotificationsComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.userNotificationCount = ko.observable(0);
            this.unreadCommentCount = ko.observable(0);
            this.recentChats = ko.observableArray([]);
            this.unreadPMCount = ko.observable(0);
            this.reload();
            $(document).on("pjax:end", function () {
                _this.reload();
            });
            var $pmDropdown = $("#pmNotificationDropdown");
            $pmDropdown.on("mouseover.pm", function () {
                $pmDropdown.off("mouseover.pm");
                _this.processing(true);
                ajaxUtils_1.AjaxUtils.get("pm/recentChats", { page: 1, onlyUnread: true })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.recentChats(result.data.chats);
                    _this.processing(false);
                });
            });
            $(document).ready(function () {
                $pmDropdown.find('[data-hover="dropdown"]')["dropdownHover"]();
            });
        }
        NotificationsComponent.prototype.reload = function () {
            var _this = this;
            var commentsContainer = $("#commentsAsync");
            if (commentsContainer.length == 0) {
                this.notificationCheck();
            }
            else {
                var subscription = commentLoadUtil_1.default.loaded.subscribe(function (value) {
                    if (value) {
                        _this.notificationCheck();
                        subscription.dispose();
                    }
                });
            }
        };
        NotificationsComponent.prototype.notificationCheck = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("notification/check", {})
                .done(function (result) {
                if (!result.isSuccessful) {
                    return;
                }
                _this.userNotificationCount(result.data.userNotificationCount);
                _this.unreadCommentCount(result.data.unreadCommentCount);
                _this.unreadPMCount(result.data.unreadPMCount);
            });
        };
        return NotificationsComponent;
    }(baseComponent_1.default));
    ko.components.register("notifications", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = NotificationsComponent;
});

},{"../utils/ajaxUtils":45,"../utils/commentLoadUtil":48,"./base/baseComponent":6,"jquery":214,"knockout":191}],23:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var SubToCollectionButtonComponent = (function (_super) {
        __extends(SubToCollectionButtonComponent, _super);
        function SubToCollectionButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.subscriptionId = ko.observable();
            this.isActive = ko.pureComputed(function () {
                return !!_this.subscriptionId();
            });
            this.subscriptionId(params.subscriptionId);
            this.collectionId = params.collectionId;
        }
        SubToCollectionButtonComponent.prototype.toggle = function () {
            var _this = this;
            if (!app.ensureAuth()) {
                return;
            }
            if (this.processing())
                return;
            this.processing(true);
            if (this.isActive()) {
                ajaxUtils_1.AjaxUtils.post("collection/unsubscribe", { subscriptionId: this.subscriptionId() })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.subscriptionId(null);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
            else {
                ajaxUtils_1.AjaxUtils.post("collection/subscribe", { id: this.collectionId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.subscriptionId(result.data);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
        };
        return SubToCollectionButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("sub-to-collection-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = SubToCollectionButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/BaseComponent":5,"knockout":191}],24:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var SubToSeriesButtonComponent = (function (_super) {
        __extends(SubToSeriesButtonComponent, _super);
        function SubToSeriesButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.subscriptionId = ko.observable();
            this.isActive = ko.pureComputed(function () {
                return !!_this.subscriptionId();
            });
            this.subscriptionId(params.subscriptionId);
            this.seriesId = params.seriesId;
        }
        SubToSeriesButtonComponent.prototype.toggle = function () {
            var _this = this;
            if (!app.ensureAuth()) {
                return;
            }
            if (this.processing())
                return;
            this.processing(true);
            if (this.isActive()) {
                ajaxUtils_1.AjaxUtils.post("work/series/unsubscribe", { subscriptionId: this.subscriptionId() })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.subscriptionId(null);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
            else {
                ajaxUtils_1.AjaxUtils.post("work/series/subscribe", { id: this.seriesId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.subscriptionId(result.data);
                })
                    .always(function () {
                    _this.processing(false);
                });
            }
        };
        return SubToSeriesButtonComponent;
    }(BaseComponent_1.default));
    ko.components.register("sub-to-series-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = SubToSeriesButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/BaseComponent":5,"knockout":191}],25:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "toastr", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var SubscribeButtonComponent = (function (_super) {
        __extends(SubscribeButtonComponent, _super);
        function SubscribeButtonComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.currentUserSubscription = ko.observable();
            this.btnCss = "";
            this.processing = ko.observable(false);
            this.mainContentMarkup = ko.pureComputed(function () {
                var currentUserSubscription = _this.currentUserSubscription(), targetUserSubscription = _this.targetUserSubscription;
                if (!currentUserSubscription) {
                    if (targetUserSubscription) {
                        return "<i class=\"icon-user-plus\"></i> Добавить в друзья";
                    }
                    return "<i class=\"icon-plus\"></i> Подписаться";
                }
                if (currentUserSubscription.isMutual) {
                    return "<i class=\"icon-users\"></i> Вы друзья <span class=\"caret\"></span>";
                }
                if (currentUserSubscription.dontShowUpdates) {
                    return "<i class=\"icon-check text-bold\"></i> Вы подписаны <span class=\"caret\"></span>";
                }
                return "<i class=\"icon-check text-bold\"></i> Вы подписаны";
            });
            this.toggleDontShowUpdatesMarkup = ko.pureComputed(function () {
                var currentUserSubscription = _this.currentUserSubscription();
                if (currentUserSubscription && currentUserSubscription.dontShowUpdates) {
                    return "<span style=\"margin-right: 22.5px\"></span>Показывать новости";
                }
                return "<i class=\"icon-check mr-sm text-bold\"></i> Показывать новости";
            });
            this.unsubscribeMarkup = ko.pureComputed(function () {
                var currentUserSubscription = _this.currentUserSubscription();
                if (currentUserSubscription && currentUserSubscription.isMutual) {
                    return "<i class=\"icon-user-minus mr-sm\"></i> Удалить из друзей";
                }
                return "<span style=\"margin-right: 22.5px\"></span>Отписаться";
            });
            this.toggle = function (toggleOnlyShowingUpdates) {
                if (_this.processing())
                    return;
                _this.processing(true);
                ajaxUtils_1.AjaxUtils.post("subscription/updateSubscription", {
                    userId: _this.userId,
                    toggleOnlyShowingUpdates: toggleOnlyShowingUpdates,
                    subscribe: !_this.currentUserSubscription()
                }).done(function (result) {
                    if (result.isSuccessful) {
                        _this.currentUserSubscription(result.data);
                        if (!result.data) {
                            var drop = $(_this.element).siblings(".dropdown").find(".btn-tether-drop").data("drop");
                            if (drop) {
                                drop.close();
                            }
                        }
                        else {
                            if (toggleOnlyShowingUpdates) {
                                if (result.data.dontShowUpdates) {
                                    toastr.success("Вы больше не будете получать уведомления о действиях пользователя.");
                                }
                                else {
                                    toastr.success("Вы снова будете получать уведомления о действиях пользователя.");
                                }
                            }
                        }
                    }
                    else if (result.isWarning) {
                        toastr.warning(result.messages[0]);
                    }
                    else {
                        alert(result.messages[0]);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            };
            if (params.subscriptionInfo) {
                this.currentUserSubscription(params.subscriptionInfo.currentUserSubscription);
                this.targetUserSubscription = params.subscriptionInfo.targetUserSubscription;
            }
            this.userId = params.userId;
            this.ignored = params.ignored;
            var mode = params.mode || "normal";
            if (mode === "small") {
                this.btnCss = "btn-sm";
            }
            if (mode === "profile-aside") {
                this.btnCss = "btn-primary";
            }
        }
        return SubscribeButtonComponent;
    }(baseComponent_1.default));
    ko.components.register("subscribe-button", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = SubscribeButtonComponent;
});

},{"../utils/ajaxUtils":45,"./base/baseComponent":6,"jquery":214,"knockout":191,"toastr":199}],26:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var UserAvatarComponent = (function (_super) {
        __extends(UserAvatarComponent, _super);
        function UserAvatarComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.cssClass = ko.pureComputed(function () {
                if (_this.online === undefined || !_this.online())
                    return _this.params.css;
                return _this.params.css + " online";
            });
            this.online = params.online;
            this.avatarUrl = params.url;
        }
        return UserAvatarComponent;
    }(baseComponent_1.default));
    ko.components.register("user-avatar", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = UserAvatarComponent;
});

},{"./base/baseComponent":6,"knockout":191}],27:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/BaseComponent", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BaseComponent_1 = require("./base/BaseComponent");
    var ko = require("knockout");
    var VideoPlayerComponent = (function (_super) {
        __extends(VideoPlayerComponent, _super);
        function VideoPlayerComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.url = ko.observable("");
            this.width = 300;
            this.height = 200;
            this.providers = [
                {
                    test_regex: /^.+(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.+)?((vkvideo)|(video))[^_&]+/,
                    url_regex: /(?:https?:\/\/)?(?:www\.)?(?:(?:vk\.com)|(?:vkvideo\.ru))(?:.+)?(?:video)([0-9a-zA-Z_\-]+)_([0-9a-zA-Z_\-]+)%?(?:.*)/g,
                    url_text: "//vk.com/video_ext.php?oid=$1&id=$2",
                    html: '<iframe width="100%" height="{height}" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                    provider: "vk"
                },
                {
                    test_regex: /^.+(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.*clip)(.+)/,
                    url_regex: /(?:https?:\/\/)?(?:www\.)?(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.*clip)([0-9a-zA-Z_\-]+)_([0-9a-zA-Z]+)(?:.*)/g,
                    url_text: "//vk.com/video_ext.php?oid=$1&id=$2",
                    html: '<iframe width="100%" height="646" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                    provider: "vk"
                },
                {
                    test_regex: /^.+(yappy.media)\/video?[^_&]+/,
                    url_regex: /(?:https?:\/\/)?(?:www\.)?(?:yappy\.media)\/(?:video)\/([0-9a-zA-Z_\-]+)/g,
                    url_text: "//yappy.media/default/embed/$1",
                    html: '<iframe width="100%" height="640" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                    provider: "yappy"
                },
                {
                    test_regex: /^.+(rutube.ru)(?!\/yappy)(?!\/live)\/[^_&\n]+/,
                    url_regex: /(?:https?:\/\/)?(?:www\.)?(?:rutube\.ru)(?:\/shorts)?(?:\/video)?(?:\/private)?\/([0-9a-zA-Z_\-]+\/\?\S*)?\s*/g,
                    url_text: "//rutube.ru/play/embed/$1",
                    html: '<iframe width="100%" height="{height}" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                    provider: "rutube"
                },
                {
                    test_regex: /^.*((youtu.be)|(youtube.com))\/((v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))?\??v?=?([^#\&\?]*).*/,
                    url_regex: /(?:https?:\/\/)?(?:www\.)?(?:m\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=|embed\/|shorts\/)?([0-9a-zA-Z_\-]+)(.+)?/g,
                    url_text: "//www.youtube.com/embed/$1",
                    html: '<iframe width="100%" height="{height}" src="{url}?wmode=opaque" frameborder="0" allowfullscreen></iframe>',
                    provider: "youtube"
                },
                {
                    test_regex: /^.*(?:vimeo.com)\/(?:channels(\/\w+\/)?|groups\/*\/videos\/\u200b\d+\/|video\/|)(\d+)(?:$|\/|\?)/,
                    url_regex: /(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:[a-zA-Z0-9_\-]+)?/i,
                    url_text: "//player.vimeo.com/video/$1",
                    html: '<iframe width="100%" height="{height}" src="{url}" frameborder="0" allowfullscreen></iframe>',
                    provider: "vimeo"
                }
            ];
            this.html = ko.computed(function () {
                var videoUrl = _this.url();
                if (!videoUrl)
                    return "";
                var providers = _this.providers;
                var width = _this.width.toString();
                var height = _this.height.toString();
                var html = "";
                for (var i = 0; i < providers.length; i++) {
                    var p = providers[i];
                    if (p.test_regex.test(videoUrl)) {
                        var embedUrl = videoUrl.replace(p.url_regex, p.url_text);
                        html = p.html
                            .replace("{url}", embedUrl)
                            .replace("{width}", width)
                            .replace("{height}", height);
                        break;
                    }
                }
                return html;
            });
            if (params.width)
                this.width = params.width;
            if (params.height)
                this.height = params.height;
            this.url(ko.utils.unwrapObservable(params.url));
        }
        return VideoPlayerComponent;
    }(BaseComponent_1.default));
    ko.components.register("video-player", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = VideoPlayerComponent;
});

},{"./base/BaseComponent":5,"knockout":191}],28:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseComponent", "knockout", "jquery", "lodash", "../utils/localStorageUtils", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseComponent_1 = require("./base/baseComponent");
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var WorksWidgetComponent = (function (_super) {
        __extends(WorksWidgetComponent, _super);
        function WorksWidgetComponent(params, element, templateNodes) {
            var _this = this;
            _super.call(this, params, element, templateNodes);
            this.isLoading = ko.observable(true);
            this.noData = ko.observable(false);
            this.url = params.url;
            this.title = params.title;
            this.requestParams = params.rParams || {};
            this.localeStoraParams = params.lsParams || {};
            _.each(this.localeStoraParams, function (rKey, lsKey) {
                _this.requestParams[rKey] = localStorageUtils_1.default.get(lsKey);
            });
            ajaxUtils_1.AjaxUtils.get(this.url, this.requestParams)
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    _this.isLoading(false);
                    return;
                }
                if (result.data.noData) {
                    _this.noData(true);
                    _this.isLoading(false);
                    setTimeout(function () {
                        $(element).find(".empty-widget").addClass("in");
                    });
                    return;
                }
                _this.isLoading(false);
                setTimeout(function () {
                    var $slick = $(element).find(".slick-container");
                    $slick.slick({
                        slidesToShow: 1,
                        slidesToScroll: 1,
                        adaptiveHeight: true,
                        responsive: [
                            {
                                breakpoint: 992,
                                settings: {
                                    slidesToShow: 1,
                                    slidesToScroll: 1
                                }
                            }, {
                                breakpoint: 768,
                                settings: {
                                    slidesToShow: 4,
                                    slidesToScroll: 4
                                }
                            }, {
                                breakpoint: 600,
                                settings: {
                                    slidesToShow: 3,
                                    slidesToScroll: 3
                                }
                            }, {
                                breakpoint: 460,
                                settings: {
                                    slidesToShow: 2,
                                    slidesToScroll: 2
                                }
                            }
                        ]
                    });
                    _.each(result.data.works, function (w) {
                        $slick.slick("slickAdd", w);
                    });
                }, 0);
            }).fail(function () {
                _this.isLoading(false);
            });
        }
        return WorksWidgetComponent;
    }(baseComponent_1.default));
    ko.components.register("works-widget", {});
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = WorksWidgetComponent;
});

},{"../utils/ajaxUtils":45,"../utils/localStorageUtils":59,"./base/baseComponent":6,"jquery":214,"knockout":191,"lodash":216}],29:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    ko.bindingHandlers["btn"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var observable = valueAccessor(), $el = $(element);
            observable.subscribe(function (isProcessing) {
                if (isProcessing) {
                    $el.attr("disabled", "disabled").addClass("is-loading");
                }
                else {
                    $el.removeAttr("disabled").removeClass("is-loading");
                }
            });
        }
    };
});

},{"jquery":214,"knockout":191}],30:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    ko.bindingHandlers["checkPermissions"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var options = ko.unwrap(valueAccessor()), $el = $(element);
            if ($el.attr("data-is-banned") === undefined && $el.attr("data-email-confirmed") === undefined)
                return;
            var isBanned = $el.attr("data-is-banned") === "true", emailConfirmed = $el.attr("data-email-confirmed") === "true";
            if (isBanned || !emailConfirmed) {
                $el.attr("disabled", "disabled")
                    .removeAttr("href")
                    .removeAttr("data-pjax");
                var hint = "";
                if (isBanned) {
                    hint = "Вы не можете это сделать, пока ваша учетная запись заблокирована.";
                }
                else {
                    hint = "Вы не можете это сделать, пока ваш электронный адрес не подтвержден.";
                }
                var hintPosition = "hint-" + (options.position || "top");
                var $span = $("<span />");
                $span.attr("data-hint", hint)
                    .addClass(hintPosition)
                    .addClass(options.css || "");
                $el.wrap($span);
            }
        }
    };
});

},{"jquery":214,"knockout":191}],31:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    ko.bindingHandlers["checkedWithInit"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var observable = valueAccessor();
            var value = $(element).attr("checked");
            if (!ko.isWriteableObservable(observable)) {
                throw new Error("Observable should be writeable");
            }
            if (value !== undefined && value === "checked") {
                observable(true);
            }
            var bindings = {
                checked: observable
            };
            ko.applyBindingsToNode(element, bindings, viewModel);
        }
    };
    ko.bindingHandlers["radioWithInit"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var observable = valueAccessor();
            var value = $(element).attr("checked");
            if (!ko.isWriteableObservable(observable)) {
                throw new Error("Observable should be writeable");
            }
            if (value) {
                observable($(element).val());
            }
            var bindings = {
                checked: observable
            };
            ko.applyBindingsToNode(element, bindings, viewModel);
        }
    };
    ko.bindingHandlers["checkedArrayWithInit"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var observable = valueAccessor();
            var isChecked = $(element).attr("checked");
            if (!ko.isWriteableObservable(observable)) {
                throw new Error("Observable should be writeable");
            }
            if (isChecked) {
                var values = observable();
                values.push($(element).val());
                observable(values);
            }
            var bindings = {
                checked: observable
            };
            ko.applyBindingsToNode(element, bindings, viewModel);
        }
    };
});

},{"knockout":191}],32:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "lodash", "moment"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    ko.bindingHandlers["datePicker"] = {
        init: function (element, valueAccessor, allBindings) {
            var $container = $(element), observable = valueAccessor();
            var customParams = allBindings.get("datePickerOptions");
            var defaultOptions = {
                locale: {
                    "format": "DD.MM.YYYY",
                    "customRangeLabel": "За период",
                    "applyLabel": "Выбрать",
                    "cancelLabel": "Отмена"
                },
                opens: "center",
                singleDatePicker: true,
                showDropdowns: true,
                linkedCalendars: false,
                buttonClasses: "btn",
                applyClass: "btn-primary"
            };
            var daterangepickerOptions = _.defaultsDeep(customParams || {}, defaultOptions);
            $container.addClass("form-control");
            function callback(startDate) {
                if (!moment.isMoment(startDate)) {
                    startDate = moment(startDate);
                }
                observable(startDate);
            }
            callback(observable());
            $container.daterangepicker(daterangepickerOptions, callback);
            var drp = $container.data("daterangepicker");
            var currentValue = moment(observable());
            drp.setStartDate(currentValue);
            drp.setEndDate(currentValue);
            observable.subscribe(function (newValue) {
                var val = newValue;
                if (newValue === null || newValue === undefined) {
                    currentValue = newValue;
                    observable(newValue);
                    $container.val(null);
                    return;
                }
                if (!moment.isMoment(val)) {
                    val = moment(val);
                }
                if (!val.isValid()) {
                    return;
                }
                if (currentValue.isSame(val)) {
                    return;
                }
                drp.setStartDate(newValue);
                drp.setEndDate(newValue);
                callback(newValue);
                currentValue = val;
            });
        }
    };
});

},{"knockout":191,"lodash":216,"moment":219}],33:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "moment", "bootstrap-daterangepicker"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var moment = require("moment");
    require("bootstrap-daterangepicker");
    ko.bindingHandlers["dateRangePicker"] = {
        init: function (element, valueAccessor, allBindings) {
            var $container = $(element), options = valueAccessor();
            var startDateObs = options.start, endDateObs = options.end;
            if (!ko.observable(startDateObs) || !ko.observable(endDateObs)) {
                throw new Error("Please specify valid \"start\" and \"end\" parameters.");
            }
            var currentDate = moment().startOf("day");
            var currentDateEnd = moment().endOf("day");
            var yesterdayDate = currentDate.clone().add(-1, "days");
            var yesterdayDateEnd = currentDateEnd.clone().add(-1, "days");
            var startOfWeek = currentDate.clone().add(-6, "days");
            var startOfMonth = currentDate.clone().add(-30, "days");
            var pastMonthStart = startOfMonth.clone().add(-1, "months");
            var pastMonthEnd = startOfMonth.clone().add(-1, "days").endOf("day");
            var threeMonths = startOfMonth.clone().add(-2, "months");
            var yearStart = currentDate.clone().add(-12, "months");
            var defaultOptions = {
                startDate: startDateObs(),
                endDate: endDateObs(),
                ranges: {
                    'За неделю': [startOfWeek, currentDateEnd],
                    'За месяц': [startOfMonth, currentDateEnd],
                    'За прошлый месяц': [pastMonthStart, pastMonthEnd],
                    'За год': [yearStart, currentDateEnd]
                },
                locale: {
                    "format": "DD MMMM YYYY",
                    "customRangeLabel": "За период",
                    "applyLabel": "Показать",
                    "cancelLabel": "Отмена"
                },
                linkedCalendars: false,
                opens: "center",
                buttonClasses: "btn",
                showDropdowns: true,
                applyClass: "btn-primary"
            };
            if (options.ranges) {
                defaultOptions.ranges = options.ranges;
            }
            var daterangepickerOptions = _.defaultsDeep(options.custom || {}, defaultOptions);
            $container.addClass("daterangepicker-container");
            var $span = $("<span/>", {
                "class": "text-caption"
            });
            $container.append("<i class=\"icon-calendar\"></i>", $span, "<b class=\"caret\"></b>");
            function formatCaptionText(startDate, endDate) {
                if (startDate.isSame(yesterdayDate) && endDate.isSame(yesterdayDateEnd)) {
                    return "За вчера";
                }
                if (startDate.isSame(currentDate) && endDate.isSame(currentDateEnd)) {
                    return "За сегодня";
                }
                if (startDate.isSame(startOfWeek) && endDate.isSame(currentDateEnd)) {
                    return "За неделю";
                }
                if (startDate.isSame(startOfMonth) && endDate.isSame(currentDateEnd)) {
                    return "За месяц";
                }
                if (startDate.isSame(pastMonthStart) && endDate.isSame(pastMonthEnd)) {
                    return "За прошлый месяц";
                }
                if (startDate.isSame(threeMonths) && endDate.isSame(currentDateEnd)) {
                    return "За 3 месяца";
                }
                if (startDate.isSame(yearStart) && endDate.isSame(currentDateEnd)) {
                    return "За год";
                }
                if (startDate.year() !== endDate.year()) {
                    return startDate.format("D MMMM YYYY") + " — " + endDate.format("D MMMM YYYY");
                }
                if (startDate.month() !== endDate.month()) {
                    return startDate.format("D MMMM") + " — " + endDate.format("D MMMM YYYY");
                }
                return startDate.format("D") + " — " + endDate.format("D MMMM YYYY");
            }
            function callback(startDate, endDate, label) {
                if (label === void 0) { label = ""; }
                if (!moment.isMoment(startDate)) {
                    startDate = moment(startDate);
                }
                if (!moment.isMoment(endDate)) {
                    endDate = moment(endDate);
                }
                $span.html(formatCaptionText(startDate, endDate));
                if (!startDate.isSame(startDateObs())) {
                    startDateObs(startDate);
                }
                if (!endDate.isSame(endDateObs())) {
                    endDateObs(endDate);
                }
            }
            callback(startDateObs(), endDateObs());
            $container.daterangepicker(daterangepickerOptions, callback);
            var drp = $container.data("daterangepicker");
            startDateObs.subscribe(function (newValue) {
                drp.setStartDate(newValue);
                callback(newValue, endDateObs());
            });
            endDateObs.subscribe(function (newValue) {
                drp.setEndDate(newValue);
                callback(startDateObs(), newValue);
            });
        }
    };
});

},{"bootstrap-daterangepicker":200,"jquery":214,"knockout":191,"lodash":216,"moment":219}],34:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "drop"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var Drop = require("drop");
    ko.bindingHandlers["drop"] = {
        init: function (element, valueAccessor, allBindings, viewModel) {
            var $btn = $(element), options = valueAccessor(), $dropContent = $btn.siblings(".tether-drop-content");
            if (options.content === undefined && $dropContent.length === 0) {
                throw new Error("Drop content not found! Please specify content options or add container with class \"tether-drop-content\" right after button.");
            }
            var dropOptions = _.defaultsDeep(options || {}, {
                target: element,
                content: $dropContent[0],
                openOn: "click",
                constrainToScrollParent: true,
                classes: "drop-theme-arrows",
                tetherOptions: {
                    attachment: "top center",
                    targetAttachment: "bottom center",
                    constraints: [
                        {
                            to: "window",
                            attachment: "together"
                        }
                    ]
                }
            });
            var drop = new Drop(dropOptions);
            $btn.addClass("btn-tether-drop");
            $btn.data("drop", drop);
            drop.once("open", function () {
                ko.applyBindingsToDescendants(viewModel, this.content);
            });
            drop.on("open", function () {
                drop.position();
                $btn.addClass("open");
            });
            drop.on("close", function () {
                $btn.removeClass("open");
            });
        }
    };
});

},{"drop":197,"jquery":214,"knockout":191,"lodash":216}],35:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "../utils/browserUtils", "../utils/windowUtils", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var browserUtils_1 = require("../utils/browserUtils");
    var windowUtils_1 = require("../utils/windowUtils");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var scriptjs = require("scriptjs");
    var typograf = require('typograf');
    var destroy = function (element) {
        var $el = $(element);
        return function () {
            if ($el.data("froala.editor")) {
                $el.froalaEditor("destroy");
            }
        };
    };
    var loadFroala = function (onLoad) {
        if ($.FroalaEditor) {
            onLoad();
            return;
        }
        var cssAnchor = $("#dynamicCss")[0];
        ajaxUtils_1.AjaxUtils.loadCss("distCommon/vendor/froala-wysiwyg-editor/css/froala_editor.pkgd.min.css?v=010417", cssAnchor);
        scriptjs([
            ajaxUtils_1.AjaxUtils.getFullUrl("distCommon/vendor/froala-wysiwyg-editor/js/froala_editor.min.js?v=010417")
        ], function () {
            scriptjs([
                ajaxUtils_1.AjaxUtils.getFullUrl("dist/vendor/froala-wysiwyg-editor/js/plugins.min.js?v=010417")
            ], function () {
                $.FroalaEditor.DefineIcon("quote", { NAME: "quote-left" });
                $.FroalaEditor.RegisterShortcut($.FE.KEYCODE.SINGLE_QUOTE, "quote", "decrease", "'", !0);
                $.FroalaEditor.RegisterCommand("quote", {
                    title: "Цитата",
                    focus: false,
                    undo: false,
                    refreshAfterCallback: false,
                    callback: function () {
                        var self = this;
                        var i, blocks = this.selection.blocks();
                        var isBlockquote = false;
                        this.selection.save();
                        for (i = 0; i < blocks.length; i++) {
                            var blockquote = $(blocks[i]).parentsUntil(this.$el, "BLOCKQUOTE")[0];
                            if (blocks[i].tagName !== "BLOCKQUOTE" && blockquote) {
                                isBlockquote = true;
                                $(blockquote).replaceWith(blockquote.innerHTML);
                            }
                        }
                        if (!isBlockquote) {
                            var $blockquote = $("<blockquote>");
                            $blockquote.insertBefore(blocks[0]);
                            for (i = 0; i < blocks.length; i++) {
                                $blockquote.append(blocks[i]);
                            }
                        }
                        this.html.unwrap(), this.selection.restore();
                    }
                });
                $.FroalaEditor.DefineIconTemplate("custom-icons", "<i class='icon-[NAME]'></i>");
                $.FroalaEditor.ICON_DEFAULT_TEMPLATE = "custom-icons";
                $.FroalaEditor.DefineIcon("typograf", { NAME: "paragraph" });
                $.FroalaEditor.RegisterCommand("typograf", {
                    title: "Оттипографить",
                    focus: false,
                    undo: true,
                    refreshAfterCallback: true,
                    callback: function () {
                        var _this = this;
                        var html = this.html.getSelected();
                        if (!html || !html.length)
                            return;
                        ajaxUtils_1.AjaxUtils.get("utils/gettypograftype", {}).done(function (result) {
                            if (!result.isSuccessful) {
                                alert(result.messages[0]);
                                return;
                            }
                            var typografType = result.data;
                            switch (typografType) {
                                case "lebedev": {
                                    _this.undo.saveStep();
                                    ajaxUtils_1.AjaxUtils.post("utils/typograf", { text: html }).done(function (result) {
                                        if (!result.isSuccessful) {
                                            alert(result.messages[0]);
                                            return;
                                        }
                                        _this.html.insert(result.data);
                                        _this.undo.saveStep();
                                        _this.events.focus();
                                        setTimeout(function () {
                                            _this.cursor.backspace();
                                        }, 0);
                                    });
                                    break;
                                }
                                default: {
                                    var tp = new typograf({ locale: ['ru', 'en-US'] });
                                    tp.enableRule('common/nbsp/replaceNbsp');
                                    var newText = tp.execute(html);
                                    _this.html.insert(newText);
                                    _this.undo.saveStep();
                                    _this.events.focus();
                                }
                            }
                        });
                    }
                });
                // Define popup template.
                $.extend($.FroalaEditor.POPUP_TEMPLATES, {
                    "spoilerPlugin.popup": "[_FORM_]"
                });
                $.FroalaEditor.PLUGINS.spoilerPlugin = function (editor) {
                    // Create custom popup.
                    function initPopup() {
                        var formHtml = "<div class='fr-spoiler-layer fr-layer fr-active'>";
                        formHtml += "<div class='fr-input-line'><input name='title' value='спойлер (показать)' type='text' " +
                            "placeholder='Название кнопки' tabIndex='1' class='fr-not-empty'><label>Название кнопки</label></div>";
                        formHtml += "</div>";
                        formHtml += "<div class='fr-action-buttons'>" +
                            "<button class='fr-command fr-submit' data-cmd='spoilerInsert' href='#' tabIndex=2 type='button'>Вставить" +
                            "</button></div></div>";
                        // Load popup template.
                        var template = {
                            form: formHtml
                        };
                        // Create popup.
                        var $popup = editor.popups.create("spoilerPlugin.popup", template);
                        return $popup;
                    }
                    // Show the popup
                    function showPopup() {
                        var html = editor.html.getSelected();
                        if (!html || !html.length) {
                            alert("Пожалуйста, выделите текст.");
                            return;
                        }
                        ;
                        // Get the popup object defined above.
                        var $popup = editor.popups.get("spoilerPlugin.popup");
                        // If popup doesn't exist then create it.
                        // To improve performance it is best to create the popup when it is first needed
                        // and not when the editor is initialized.
                        if (!$popup)
                            $popup = initPopup();
                        // Set the editor toolbar as the popup's container.
                        editor.popups.setContainer("spoilerPlugin.popup", editor.$tb);
                        // This will trigger the refresh event assigned to the popup.
                        // editor.popups.refresh('customPlugin.popup');
                        // This custom popup is opened by pressing a button from the editor's toolbar.
                        // Get the button's object in order to place the popup relative to it.
                        var $btn = editor.$tb.find('.fr-command[data-cmd="spoiler"]');
                        // Set the popup's position.
                        var left = $btn.offset().left + $btn.outerWidth() / 2;
                        var top = $btn.offset().top + (editor.opts.toolbarBottom ? 10 : $btn.outerHeight() - 10);
                        editor.selection.save();
                        // Show the custom popup.
                        // The button's outerHeight is required in case the popup needs to be displayed above it.
                        editor.popups.show("spoilerPlugin.popup", left, top, $btn.outerHeight());
                    }
                    // Hide the custom popup.
                    function hidePopup() {
                        editor.popups.hide("spoilerPlugin.popup");
                    }
                    function getPopupTitle() {
                        return editor.popups.get("spoilerPlugin.popup").find("input[name='title']").val();
                    }
                    // Methods visible outside the plugin.
                    return {
                        showPopup: showPopup,
                        hidePopup: hidePopup,
                        getPopupTitle: getPopupTitle
                    };
                };
                // Define an icon and command for the button that opens the custom popup.
                $.FroalaEditor.DefineIcon("spoiler", { NAME: "eye-slash" });
                $.FroalaEditor.RegisterCommand("spoiler", {
                    title: "Спойлер",
                    undo: false,
                    focus: false,
                    plugin: "spoilerPlugin",
                    callback: function () {
                        if (!this.popups.isVisible("spoilerPlugin.popup")) {
                            this.spoilerPlugin.showPopup();
                        }
                        else {
                            if (this.$el.find(".fr-marker")) {
                                this.events.disableBlur();
                                this.selection.restore();
                            }
                            this.popups.hide("spoilerPlugin.popup");
                        }
                    }
                });
                $.FroalaEditor.RegisterCommand("spoilerInsert", {
                    focus: false,
                    refreshAfterCallback: false,
                    undo: true,
                    callback: function () {
                        var popupTitle = this.spoilerPlugin.getPopupTitle();
                        if (!popupTitle || !popupTitle.length)
                            return;
                        this.selection.restore();
                        var html = this.html.getSelected();
                        this.undo.saveStep();
                        this.spoilerPlugin.hidePopup();
                        this.html.insert("[spoiler=" + popupTitle + "]" + html + "[/spoiler]");
                        this.undo.saveStep();
                        this.events.focus();
                    }
                });
                $.FroalaEditor.DefineIcon("paragraphFormat", { NAME: "header" });
                $.FroalaEditor.VIDEO_PROVIDERS = [
                    {
                        test_regex: /^.+(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.+)?((vkvideo)|(video))[^_&]+/,
                        url_regex: /(?:https?:\/\/)?(?:www\.)?(?:(?:vk\.com)|(?:vkvideo\.ru))(?:.+)?(?:video)([0-9a-zA-Z_\-]+)_([0-9a-zA-Z_\-]+)%?(?:.*)/g,
                        url_text: "//vk.com/video_ext.php?oid=$1&id=$2",
                        html: '<iframe width="640" height="360" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                        provider: "vk"
                    },
                    {
                        test_regex: /^.+(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.*clip)(.+)/,
                        url_regex: /(?:https?:\/\/)?(?:www\.)?(?:(?:vk\.com)|(?:vkvideo\.ru))\/(?:.*clip)([0-9a-zA-Z_\-]+)_([0-9a-zA-Z]+)(?:.*)/g,
                        url_text: "//vk.com/video_ext.php?oid=$1&id=$2",
                        html: '<iframe width="325" height="646" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                        provider: "vk"
                    },
                    {
                        test_regex: /^.+(yappy.media)\/video?[^_&]+/,
                        url_regex: /(?:https?:\/\/)?(?:www\.)?(?:yappy\.media)\/(?:video)\/([0-9a-zA-Z_\-]+)/g,
                        url_text: "//yappy.media/default/embed/$1",
                        html: '<iframe width="360" height="640" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                        provider: "yappy"
                    },
                    {
                        test_regex: /^.+(rutube.ru)(?!\/yappy)(?!\/live)\/[^_&\n]+/,
                        url_regex: /(?:https?:\/\/)?(?:www\.)?(?:rutube\.ru)(?:\/shorts)?(?:\/video)?(?:\/private)?\/([0-9a-zA-Z_\-]+\/\?\S*)?\s*/g,
                        url_text: "//rutube.ru/play/embed/$1",
                        html: '<iframe width="640" height="360" src="{url}" frameborder="0" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true"></iframe>',
                        provider: "rutube"
                    },
                    {
                        test_regex: /^.*((youtu.be)|(youtube.com))\/((v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))?\??v?=?([^#\&\?]*).*/,
                        url_regex: /(?:https?:\/\/)?(?:www\.)?(?:m\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=|embed\/|shorts\/)?([0-9a-zA-Z_\-]+)(.+)?/g,
                        url_text: "//www.youtube.com/embed/$1",
                        html: '<iframe width="640" height="360" src="{url}?wmode=opaque" frameborder="0" allowfullscreen></iframe>',
                        provider: "youtube"
                    },
                    {
                        test_regex: /^.*(?:vimeo.com)\/(?:channels(\/\w+\/)?|groups\/*\/videos\/\u200b\d+\/|video\/|)(\d+)(?:$|\/|\?)/,
                        url_regex: /(?:https?:\/\/)?(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/(?:[^\/]*)\/videos\/|album\/(?:\d+)\/video\/|video\/|)(\d+)(?:[a-zA-Z0-9_\-]+)?/i,
                        url_text: "//player.vimeo.com/video/$1",
                        html: '<iframe width="640" height="360" src="{url}" frameborder="0" allowfullscreen></iframe>',
                        provider: "vimeo"
                    }
                ];
                $.FroalaEditor.VIDEO_EMBED_REGEX = /((<iframe(\n*.)*><\/iframe>)|(<embed.*>))/i;
                onLoad();
            });
        });
    };
    var getDefaultOptions = function () {
        var rootUrl = window["app"].rootUrl;
        var defaultOptions = {
            language: "ru",
            key: "eQZMe1NJGC1HTMVANU==",
            imageUploadURL: rootUrl + "file/froalaUploadImage",
            imagePaste: false,
            imageUploadMethod: "POST",
            imageMaxSize: 5 * 1024 * 1024,
            linkInsertButtons: ["linkBack"],
            linkEditButtons: ["linkOpen", "linkEdit", "linkRemove"],
            tableEditButtons: ["tableRows", "tableColumns", "tableCells", "tableCellBackground",
                "tableCellVerticalAlign", "tableCellHorizontalAlign", "tableRemove"],
            imageEditButtons: ["imageReplace", "imageAlign", "imageDisplay",
                "|", "imageLink", "linkOpen", "linkEdit", "linkRemove",
                "-", "imageAlt", "imageSize", "imageRemove"],
            imageDefaultWidth: 0,
            typingTimer: 250,
            htmlAllowComments: false,
            wordPasteModal: false,
            wordAllowedStyleProps: ["background", "color", "width", "text-align", "vertical-align", "background-color"],
            videoDefaultDisplay: "block",
            videoInsertButtons: ["videoBack", "|", "videoByURL", "videoEmbed"],
            htmlAllowedTags: [
                "a", "b", "blockquote", "br", "s", "h2",
                "cite", "code", "col", "colgroup", "del", "details",
                "div", "em", "embed", "hr", "i", "iframe", "img", "li",
                "ol", "p", "pre", "small", "span", "strike",
                "strong", "sub", "sup", "table", "dd",
                "tbody", "td", "th", "thead",
                "time", "tr", "u", "ul", "video"
            ],
            toolbarButtons: [
                "bold", "italic", "underline", "strikeThrough", "|",
                "quote", "align", "paragraphFormat", "typograf", "spoiler", "color", "emoticons", "inlineStyle",
                "formatOL", "formatUL",
                //"insertHR", "-", "undo", "redo",
                "insertLink", "insertImage", "insertVideo", "insertFile", "insertTable", "fullscreen", "html", "|", "undo", "redo"
            ],
            toolbarButtonsMD: [
                "bold", "italic", "underline", "strikeThrough", "|",
                "quote", "align", "paragraphFormat", "typograf", "spoiler", "color", "emoticons", "inlineStyle",
                "formatOL", "formatUL",
                // "insertHR", "-", "undo", "redo",
                "insertLink", "insertImage", "insertVideo", "insertFile", "insertTable", "fullscreen", "html", "|", "undo", "redo"
            ],
            toolbarButtonsSM: [
                "bold", "italic", "underline", "strikeThrough", "|",
                "quote", "align", "paragraphFormat", "typograf", "spoiler", "color", "emoticons",
                "paragraphFormat", "formatOL", "formatUL",
                //"insertHR", "-", "undo", "redo",
                "insertLink", "insertImage", "insertVideo", "insertFile", "insertTable", "fullscreen", "html"
            ],
            toolbarButtonsXS: [
                "bold", "italic", "strikeThrough", "|", "quote", "insertLink", "insertImage", "insertVideo", "fullscreen", "|", "undo", "redo"
            ],
            paragraphFormat: {
                N: "Обычный текст",
                H2: "Подзаголовок"
            },
            emoticonsSet: [
                { code: "1f642", desc: "Slightly smiling face" },
                { code: "1f600", desc: "Grinning face" },
                { code: "1f602", desc: "Face with tears of joy" },
                { code: "1f605", desc: "Smiling face with open mouth and cold sweat" },
                { code: "1f606", desc: "Smiling face with open mouth and tightly-closed eyes" },
                { code: "1f607", desc: "Smiling face with halo" },
                { code: "1f608", desc: "Smiling face with horns" },
                { code: "1f609", desc: "Winking face" },
                { code: "1f60a", desc: "Smiling face with smiling eyes" },
                { code: "1f60b", desc: "Face savoring delicious food" },
                { code: "1f60d", desc: "Smiling face with heart-shaped eyes" },
                { code: "1f60e", desc: "Smiling face with sunglasses" },
                { code: "1f913", desc: "Nerd face" },
                { code: "1f60f", desc: "Smirking face" },
                { code: "1f610", desc: "Neutral face" },
                { code: "1f612", desc: "Unamused face" },
                { code: "1f613", desc: "Face with cold sweat" },
                { code: "1f614", desc: "Pensive face" },
                { code: "1f615", desc: "Confused face" },
                { code: "1f618", desc: "Face throwing a kiss" },
                { code: "1f917", desc: "hugging face" },
                { code: "1f61d", desc: "Face with stuck out tongue" },
                { code: "1f641", desc: "Slightly frowning face" },
                { code: "1f61e", desc: "Disappointed face" },
                { code: "1f621", desc: "Pouting face" },
                { code: "1f622", desc: "Crying face" },
                { code: "1f623", desc: "Persevering face" },
                { code: "1f625", desc: "Disappointed but relieved face" },
                { code: "1f627", desc: "Anguished face" },
                { code: "1f628", desc: "Fearful face" },
                { code: "1f62a", desc: "Sleepy face" },
                { code: "1f62b", desc: "Tired face" },
                { code: "1f62c", desc: "Grimacing face" },
                { code: "1f62d", desc: "Loudly crying face" },
                { code: "1f62f", desc: "Hushed face" },
                { code: "1f630", desc: "Face with open mouth and cold sweat" },
                { code: "1f631", desc: "Face screaming in fear" },
                { code: "1f632", desc: "Astonished face" },
                { code: "1f633", desc: "Flushed face" },
                { code: "1f634", desc: "Sleeping face" },
                { code: "1f635", desc: "Dizzy face" },
                { code: "1f63a", desc: "Smiling cat face with open mouth" },
                { code: "1f639", desc: "Cat face with tears of joy" },
                { code: "1f63b", desc: "Smiling cat face with heart-eyes" },
                { code: "1f640", desc: "Weary cat face" },
                { code: "1f44d", desc: "Thumbs up sign" },
                { code: "1f44e", desc: "Thumbs down sign" },
                { code: "270c", desc: "Victory hand" },
                { code: "1f91d", desc: "Handshake" },
                { code: "1f37f", desc: "Popcorn" },
                { code: "1f37a", desc: "Beer mug" },
                { code: "1f37b", desc: "Clinking beer mugs" },
                { code: "1f942", desc: "Clinking glasses" },
                { code: "1f379", desc: "Tropical drink" },
                { code: "1f37e", desc: "Bottle with popping cork" },
                { code: "1f370", desc: "Shortcake" },
                { code: "1f382", desc: "Birthday cake" },
                { code: "1f3c6", desc: "Trophy" },
                { code: "1f381", desc: "Wrapped present" },
                { code: "1f389", desc: "Party popper" },
                { code: "2764", desc: "Heart" },
                { code: "1f494", desc: "Broken heart" },
                { code: "1f339", desc: "Rose" },
                { code: "1f490", desc: "Bouquet" },
                { code: "1f31f", desc: "Glowing star" },
                { code: "1f525", desc: "Fire" },
                { code: "1f648", desc: "See-no-evil monkey" },
                { code: "1f649", desc: "Hear-no-evil monkey" },
                { code: "1f64a", desc: "Speak-no-evil monkey" },
                { code: "1f43a", desc: "Wolf face" },
                { code: "1f984", desc: "Unicorn face" },
                { code: "1f40c", desc: "Snail" }
            ]
        };
        return defaultOptions;
    };
    ko.bindingHandlers["froala"] = {
        init: function (element, value, bindings) {
            var $el = $(element);
            $el.hide();
            loadFroala(function () {
                var model = value();
                var allBindings = ko.unwrap(bindings());
                var options = ko.toJS(allBindings.froalaOptions) || {};
                if (model.isModified) {
                    var text = $el.val() || "";
                    model(text);
                    setTimeout(function () {
                        model.isModified(false);
                    }, 50);
                }
                options = _.defaults(options, getDefaultOptions());
                // initialize the editor
                $el.froalaEditor(options);
                var editor = $el.data("froala.editor");
                //$el.on("froalaEditor.focus", function (e, editor) {
                //    $el.siblings(".fr-box").addClass("focused");
                //});
                //$el.on("froalaEditor.blur", function (e, editor) {
                //    $el.siblings(".fr-box").removeClass("focused");
                //});
                // provide froala editor instance for flexibility
                if (allBindings.froalaInstance && ko.isWriteableObservable(allBindings.froalaInstance)) {
                    allBindings.froalaInstance($el.data(editor));
                }
                if (allBindings.froalaSubmit) {
                    $el.on("froalaEditor.keydown", function (e, editor, keydownEvent) {
                        if ((keydownEvent.keyCode == 10 || keydownEvent.keyCode == 13) && keydownEvent.ctrlKey) {
                            // Ctrl-Enter pressed
                            allBindings.froalaSubmit();
                        }
                    });
                }
                // update underlying model whenever editor content changed
                $el.on("froalaEditor.contentChanged", function (e, editor) {
                    if (ko.isWriteableObservable(model)) {
                        var editorValue = editor.html.get();
                        var current = model();
                        if (current !== editorValue) {
                            if (options.dirtyWhenUpdate) {
                                windowUtils_1.default.setDirty();
                            }
                            model(editorValue);
                        }
                    }
                });
                // Грязный хак чтобы работало обновление в мобильных браузерах
                var interval;
                if (browserUtils_1.default.isMobile()) {
                    interval = setInterval(function () {
                        var editorValue = editor.html.get();
                        var current = model();
                        if (current !== editorValue) {
                            model(editorValue);
                        }
                    }, 1000);
                }
                // cleanup editor, when dom node is removed
                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                    destroy(element);
                    if (interval) {
                        try {
                            clearInterval(interval);
                        }
                        catch (e) {
                        }
                    }
                });
                var unsupportedVideoUrlRegex = /dzen.ru/;
                $el.on("froalaEditor.video.linkError", function (ev, el, url) {
                    var alertText = unsupportedVideoUrlRegex.test(url)
                        ? 'Вставить по ссылке нельзя. Используйте вариант "Вставить как код"'
                        : 'Данный видеосервис не поддерживается';
                    alert(alertText);
                });
            });
            // do not handle child nodes
            return { controlsDescendantBindings: true };
        },
        update: function (element, value) {
            var $el = $(element);
            var modelValue = ko.unwrap(value());
            var editorInstance = $el.data("froala.editor");
            if (editorInstance == null) {
                return;
            }
            var editorValue = editorInstance.html.get();
            // avoid any un-necessary updates
            if (editorValue !== modelValue && (typeof modelValue === "string" || modelValue === null)) {
                editorInstance.html.set(modelValue);
            }
        }
    };
});



},{"../utils/ajaxUtils":45,"../utils/browserUtils":47,"../utils/windowUtils":72,"jquery":214,"knockout":191,"lodash":216,"scriptjs":194,"typograf":227}],36:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "readmore"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var imagesLoaded = require("imagesloaded");
    require("readmore");
    ko.bindingHandlers["read-more"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var $el = $(element);
            var options = valueAccessor();
            var moreLinkText = options.moreLinkText || "показать все";
            var defaultOptions = {
                moreLink: "<a class=\"special-link rm-expand\" href=\"#\">" + moreLinkText + "</a>",
                lessLink: "<a class=\"special-link rm-collapse\" href=\"#\">свернуть</a>",
                embedCSS: false,
                collapsedHeight: 84
            };
            options = _.defaults(options, defaultOptions);
            if ($el.find("img").length > 0) {
                $el.on('lazyloaded', function (e) {
                    // Только если загрузка не произошла при открытии спойлера
                    if (!$(e.target).parents('.panel-collapse').parents(".spoiler").length) {
                        $el.readmore(options);
                    }
                });
            }
            else {
                $el.readmore(options);
            }
            if ($el.find(".spoiler").length > 0) {
                $el.find(".spoiler").on("show.bs.collapse", function () {
                    $el.readmore("destroy");
                });
            }
        }
    };
});

},{"imagesloaded":212,"jquery":214,"knockout":191,"lodash":216,"readmore":182}],37:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "../utils/richContentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var richContentUtils_1 = require("../utils/richContentUtils");
    ko.bindingHandlers["richContent"] = {
        init: function () {
            // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
            return { "controlsDescendantBindings": true };
        },
        update: function (element, valueAccessor) {
            // setHtml will unwrap the value if needed
            var html = "<div class='rich-content'>" + ko.unwrap(valueAccessor()) + "</div>";
            ko.utils.setHtml(element, html);
            richContentUtils_1.default.processHtml($(element));
        }
    };
});

},{"../utils/richContentUtils":67,"jquery":214,"knockout":191}],38:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "../utils/stringUtils", "select2"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    var stringUtils_1 = require("../utils/stringUtils");
    require("select2");
    var defaultOptions = {
        minimumResultsForSearch: Infinity,
        language: {
            errorLoading: function () {
                return "Невозможно загрузить результаты";
            },
            inputTooLong: function (args) {
                var overChars = args.input.length - args.maximum;
                var message = "Пожалуйста, введите на " + overChars + " символ";
                message += stringUtils_1.default.pluralize(overChars, ["", "a", "ов"]);
                message += " меньше";
                return message;
            },
            inputTooShort: function (args) {
                var remainingChars = args.minimum - args.input.length;
                var message = "Пожалуйста, введите еще хотя бы " + remainingChars +
                    " символ";
                message += stringUtils_1.default.pluralize(remainingChars, ["", "a", "ов"]);
                return message;
            },
            loadingMore: function () {
                return "Загрузка данных…";
            },
            maximumSelected: function (args) {
                var message = "Вы можете выбрать не более " + args.maximum + " элемент";
                message += stringUtils_1.default.pluralize(args.maximum, ["", "a", "ов"]);
                return message;
            },
            noResults: function () {
                return "Совпадений не найдено";
            },
            searching: function () {
                return "Поиск…";
            }
        }
    };
    ko.bindingHandlers["select2"] = {
        init: function (el, valueAccessor, allBindingsAccessor, viewModel) {
            ko.utils.domNodeDisposal.addDisposeCallback(el, function () {
                $(el).select2("destroy");
            });
            var select2Options = ko.utils.unwrapObservable(valueAccessor());
            $(el).select2(_.defaultsDeep(select2Options, defaultOptions));
            // Для мультиселекта сохраняем порядок выбора
            if ($(el).prop("multiple")) {
                $(el).on("select2:select", function (e) {
                    var elm = e.params.data.element, $elm = $(elm), $t = $(this);
                    $t.append($elm);
                    $t.trigger("change.select2");
                });
            }
        },
        update: function (el, valueAccessor, allBindingsAccessor, viewModel) {
            var allBindings = allBindingsAccessor();
            if ("value" in allBindings) {
                if (allBindings.select2.multiple && allBindings.value().constructor !== Array) {
                    $(el).select2("val", allBindings.value().split(","));
                }
                else {
                    $(el).select2("val", allBindings.value());
                }
            }
            else if ("selectedOptions" in allBindings) {
                var converted = [];
                var textAccessor = function (value) { return value; };
                if ("optionsText" in allBindings) {
                    textAccessor = function (value) {
                        var valueAccessor = function (item) { return item; };
                        if ("optionsValue" in allBindings) {
                            valueAccessor = function (item) { return item[allBindings.optionsValue]; };
                        }
                        var items = $.grep(allBindings.options(), function (e) { return (valueAccessor(e) === value); });
                        if (items.length === 0 || items.length > 1) {
                            return "UNKNOWN";
                        }
                        return items[0][allBindings.optionsText];
                    };
                }
                $.each(allBindings.selectedOptions(), function (key, value) {
                    converted.push({ id: value, text: textAccessor(value) });
                });
                $(el).select2("data", converted);
            }
        }
    };
});

},{"../utils/stringUtils":69,"jquery":214,"knockout":191,"lodash":216,"select2":180}],39:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "sortable", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var Sortable = require("sortable");
    var ko = require("knockout");
    var swap = function (array, x, y) {
        var b = array[x];
        array[x] = array[y];
        array[y] = b;
        return array;
    };
    ko.utils["moveTo"] = function (currentIndex, newIndex) {
        var array = ko.unwrap(this);
        if (currentIndex >= array.length || currentIndex < 0 || newIndex >= array.length || newIndex < 0)
            return;
        array.splice(newIndex, 0, array.splice(currentIndex, 1)[0]);
        this(array);
    };
    ko.utils["moveUp"] = function (x) {
        var array = ko.unwrap(this), item = ko.unwrap(x);
        var index = ko.utils.arrayIndexOf(array, item);
        if (index === -1)
            return;
        if (index === 0) {
            array.push(array.shift());
        }
        else {
            swap(array, index, index - 1);
        }
        this(array);
    };
    ko.utils["moveDown"] = function (x) {
        var array = ko.unwrap(this), item = ko.unwrap(x);
        var index = ko.utils.arrayIndexOf(array, item);
        if (index === -1)
            return;
        if (index === array.length - 1) {
            array.unshift(array.pop());
        }
        else {
            swap(array, index, index + 1);
        }
        this(array);
    };
    var init = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {
        var options = buildOptions(valueAccessor, sortableOptions);
        // It's seems that we cannot update the eventhandlers after we've created
        // the sortable, so define them in init instead of update
        ['onStart', 'onEnd', 'onRemove', 'onAdd', 'onUpdate', 'onSort', 'onFilter', 'onMove', 'onClone'].forEach(function (e) {
            if (options[e] || eventHandlers[e])
                options[e] = function (eventType, parentVM, parentBindings, handler, e) {
                    var itemVM = ko.dataFor(e.item), 
                    // All of the bindings on the parent element
                    bindings = ko.utils.peekObservable(parentBindings()), 
                    // The binding options for the draggable/sortable binding of the parent element
                    bindingHandlerBinding = bindings.sortable || bindings.draggable, 
                    // The collection that we should modify
                    collection = bindingHandlerBinding.collection || bindingHandlerBinding.foreach;
                    if (handler)
                        handler(e, itemVM, parentVM, collection, bindings);
                    if (eventHandlers[eventType])
                        eventHandlers[eventType](e, itemVM, parentVM, collection, bindings);
                }.bind(undefined, e, viewModel, allBindings, options[e]);
        });
        var sortableElement = new Sortable(element, options);
        // Destroy the sortable if knockout disposes the element it's connected to
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            sortableElement.destroy();
        });
        return ko.bindingHandlers.template.init(element, valueAccessor);
    }, update = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {
        // There seems to be some problems with updating the options of a sortable
        // Tested to change eventhandlers and the group options without any luck
        return ko.bindingHandlers.template.update(element, valueAccessor, allBindings, viewModel, bindingContext);
    }, eventHandlers = (function (handlers) {
        var moveOperations = [], tryMoveOperation = function (e, itemVM, parentVM, collection, parentBindings) {
            // A move operation is the combination of a add and remove event,
            // this is to make sure that we have both the target and origin collections
            var currentOperation = { event: e, itemVM: itemVM, parentVM: parentVM, collection: collection, parentBindings: parentBindings }, existingOperation = moveOperations.filter(function (op) {
                return op.itemVM === currentOperation.itemVM;
            })[0];
            if (!existingOperation) {
                moveOperations.push(currentOperation);
            }
            else {
                // We're finishing the operation and already have a handle on
                // the operation item meaning that it's safe to remove it
                moveOperations.splice(moveOperations.indexOf(existingOperation), 1);
                var removeOperation = currentOperation.event.type === 'remove' ? currentOperation : existingOperation, addOperation = currentOperation.event.type === 'add' ? currentOperation : existingOperation;
                moveItem(itemVM, removeOperation.collection, addOperation.collection, addOperation.event.clone, addOperation.event);
            }
        }, 
        // Moves an item from the "from" collection to the "to" collection, these
        // can be references to the same collection which means it's a sort.
        // clone indicates if we should move or copy the item into the new collection
        moveItem = function (itemVM, from, to, clone, e) {
            // Unwrapping this allows us to manipulate the actual array
            var fromArray = from(), 
            // It's not certain that the items actual index is the same
            // as the index reported by sortable due to filtering etc.
            originalIndex = fromArray.indexOf(itemVM), newIndex = e.newIndex;
            // We have to find out the actual desired index of the to array,
            // as this might be a computed array. We could otherwise potentially
            // drop an item above the 3rd visible item, but the 2nd visible item
            // has an actual index of 5.
            //if (e.item.previousElementSibling) {
            //    newIndex = to().indexOf(ko.dataFor(e.item.previousElementSibling)) + 1;
            //}
            // Remove sortables "unbound" element
            e.item.parentNode.removeChild(e.item);
            // This splice is necessary for both clone and move/sort
            // In sort/move since it shouldn't be at this index/in this array anymore
            // In clone since we have to work around knockouts valuHasMutated
            // when manipulating arrays and avoid a "unbound" item added by sortable
            fromArray.splice(originalIndex, 1);
            // Update the array, this will also remove sortables "unbound" clone
            from.valueHasMutated();
            if (clone && from !== to) {
                // Read the item
                fromArray.splice(originalIndex, 0, itemVM);
                // Force knockout to update
                from.valueHasMutated();
            }
            // Force deferred tasks to run now, registering the removal
            ko.tasks.runEarly();
            // Insert the item on its new position
            to().splice(newIndex, 0, itemVM);
            // Make sure to tell knockout that we've modified the actual array.
            to.valueHasMutated();
        };
        handlers["onRemove"] = tryMoveOperation;
        handlers["onAdd"] = tryMoveOperation;
        handlers["onUpdate"] = function (e, itemVM, parentVM, collection, parentBindings) {
            // This will be performed as a sort since the to/from collections
            // reference the same collection and clone is set to false
            moveItem(itemVM, collection, collection, false, e);
        };
        return handlers;
    })({}), 
    // bindingOptions are the options set in the "data-bind" attribute in the ui.
    // options are custom options, for instance draggable/sortable specific options
    buildOptions = function (bindingOptions, options) {
        // deep clone/copy of properties from the "from" argument onto
        // the "into" argument and returns the modified "into"
        var merge = function (into, from) {
            for (var prop in from) {
                if (Object.prototype.toString.call(from[prop]) === '[object Object]') {
                    if (Object.prototype.toString.call(into[prop]) !== '[object Object]') {
                        into[prop] = {};
                    }
                    into[prop] = merge(into[prop], from[prop]);
                }
                else
                    into[prop] = from[prop];
            }
            return into;
        }, 
        // unwrap the supplied options
        unwrappedOptions = ko.utils.peekObservable(bindingOptions())["options"] || {};
        // Make sure that we don't modify the provided settings object
        options = merge({}, options);
        // group is handled differently since we should both allow to change
        // a draggable to a sortable (and vice versa), but still be able to set
        // a name on a draggable without it becoming a drop target.
        if (unwrappedOptions.group && Object.prototype.toString.call(unwrappedOptions.group) !== '[object Object]') {
            // group property is a name string declaration, convert to object.
            unwrappedOptions.group = { name: unwrappedOptions.group };
        }
        return merge(options, unwrappedOptions);
    };
    ko.bindingHandlers["draggable"] = {
        sortableOptions: {
            group: { pull: 'clone', put: false },
            sort: false
        },
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers["draggable"]["sortableOptions"]);
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers["draggable"]["sortableOptions"]);
        }
    };
    ko.bindingHandlers["sortable"] = {
        sortableOptions: {
            group: { pull: true, put: true }
        },
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers["sortable"]["sortableOptions"]);
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers["sortable"]["sortableOptions"]);
        }
    };
});

},{"knockout":191,"sortable":196}],40:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "lodash", "sumoSelect"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var _ = require("lodash");
    require("sumoSelect");
    ko.bindingHandlers["sumo-select"] = {
        init: function (element, valueAccessor, allBindingsAccessor) {
            var $el = $(element), options = valueAccessor(), allBindings = allBindingsAccessor();
            var defaultOptions = {};
            var forceUpdate = function (newValue) {
                $el.val(newValue);
                element.sumo.reload();
            };
            if (allBindings.value) {
                allBindings.value.forceUpdate = function (newValue) {
                    allBindings.value(newValue);
                    $el.val(newValue);
                    setTimeout(function () {
                        element.sumo.reload();
                    }, 0);
                };
            }
            else if (allBindings.selectedOptions) {
                allBindings.selectedOptions.forceUpdate = function (newValue) {
                    allBindings.selectedOptions(newValue);
                    $el.val(newValue);
                    setTimeout(function () {
                        element.sumo.reload();
                    }, 0);
                };
                allBindings.selectedOptions($el.val());
            }
            if (allBindings.options) {
                allBindings.options.forceUpdate = function (newValue) {
                    allBindings.options(newValue);
                    setTimeout(function () {
                        element.sumo.reload();
                    }, 0);
                };
            }
            setTimeout(function () {
                $el.sumoSelect(_.defaults(options, defaultOptions));
            }, 0);
        }
    };
});

},{"jquery":214,"knockout":191,"lodash":216,"sumoSelect":181}],41:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "jquery", "moment", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var $ = require("jquery");
    var moment = require("moment");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    ko.bindingHandlers["time"] = {
        update: function (element, valueAccessor, allBindings) {
            var value = ko.unwrap(valueAccessor()), $el = $(element), time = moment(value);
            if (!time.isValid()) {
                return;
            }
            var format = allBindings.get("format");
            var hintPosition = "hint-" + (allBindings.get("hintPosition") || "top");
            var formattedText;
            if (format === undefined || format === null || format.indexOf("calendar") !== -1) {
                formattedText = dateTimeUtils_1.default.formatCalendar(time, format);
            }
            else {
                formattedText = time.format(format);
            }
            $el.attr("data-hint", time.format("D MMMM YYYY в HH:mm:ss"));
            $el.addClass(hintPosition);
            $el.html(formattedText);
        }
    };
});

},{"../utils/dateTimeUtils":52,"jquery":214,"knockout":191,"moment":219}],42:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    ko.bindingHandlers["valueWithInit"] = {
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var observable = valueAccessor();
            var value = element.value;
            if (!ko.isWriteableObservable(observable)) {
                throw new Error("Observable should be writeable");
            }
            if (value) {
                observable(value);
            }
            else if (element.type === "date" && element.defaultValue) {
                value = new Date(element.defaultValue);
                observable(value);
                setTimeout(function () {
                    var datepicker = $(element).data("kendoDatePicker");
                    datepicker.value(value);
                }, 100);
            }
            var bindings = {
                value: observable
            };
            var valueUpdate = allBindings.get("valueUpdate");
            if (valueUpdate) {
                bindings["valueUpdate"] = valueUpdate;
            }
            ko.applyBindingsToNode(element, bindings, viewModel);
        }
    };
});

},{"knockout":191}],43:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var StickySidebar = (function () {
        function StickySidebar() {
        }
        StickySidebar.init = function (el, options) {
            var config = $.extend({
                headerSelector: ".navbar-fixed-top",
                navSelector: "",
                contentSelector: ".content",
                footerSelector: "footer",
                sidebarTopMargin: 64,
                footerThreshold: 165
            }, options);
            var fixSidebar = function () {
                var sidebarSelector = $(this);
                var viewportHeight = $(window).height();
                var documentHeight = $(document).height();
                var headerHeight = $(config.headerSelector).outerHeight();
                var navHeight = $(config.navSelector).outerHeight();
                var sidebarHeight = sidebarSelector.height() + 80;
                if ($(sidebarSelector).hasClass("sticky")) {
                    {
                        sidebarHeight -= 15;
                    }
                }
                var contentHeight = $(config.contentSelector).outerHeight();
                var footerHeight = $(config.footerSelector).outerHeight();
                var scrollTop = $(window).scrollTop();
                var breakingPoint1 = headerHeight > navHeight ? headerHeight : navHeight;
                var breakingPoint2 = documentHeight - (sidebarHeight + footerHeight + config.footerThreshold);
                // calculate
                if ((contentHeight > sidebarHeight) && (viewportHeight + 15 > sidebarHeight)) {
                    if (scrollTop < breakingPoint1) {
                        sidebarSelector.removeClass("sticky");
                    }
                    else if ((scrollTop >= breakingPoint1) && (scrollTop < breakingPoint2)) {
                        sidebarSelector.addClass("sticky").css("top", config.sidebarTopMargin);
                    }
                    else {
                        var negative = breakingPoint2 - scrollTop;
                        sidebarSelector.addClass("sticky").css("top", negative);
                    }
                }
                else {
                    sidebarSelector.removeClass("sticky");
                }
            };
            return $(el).each(function () {
                $(window).on("scroll", $.proxy(fixSidebar, this));
                $(window).on("resize", $.proxy(fixSidebar, this));
                $.proxy(fixSidebar, this)();
            });
        };
        return StickySidebar;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = StickySidebar;
});

},{"jquery":214}],44:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var scriptjs = require("scriptjs");
    $.ajaxSettings.traditional = true;
    var ApiResult = (function () {
        function ApiResult() {
        }
        return ApiResult;
    }());
    exports.ApiResult = ApiResult;
    var AjaxUtils = (function () {
        function AjaxUtils() {
        }
        AjaxUtils.handleError = function (xhr) {
            var error;
            try {
                error = xhr.responseText;
            }
            catch (ex) {
                error = xhr;
            }
            if (error) {
                console.error(error);
            }
        };
        AjaxUtils.ajaxQuery = function (url, method, data, cache, cors) {
            if (cors === void 0) { cors = false; }
            var options = {
                type: method,
                headers: method === "POST" ? this.getHeaders() : {},
                url: this.getFullUrl(url),
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                data: data,
                cache: cache
            };
            if (cors) {
                options.xhrFields = {
                    withCredentials: true
                };
            }
            var ajax = $.ajax(options);
            ajax.fail(this.handleError);
            return ajax;
        };
        AjaxUtils.getFullUrl = function (url) {
            if (url.substring(0, window["app"].rootUrl.length).toLowerCase() === window["app"].rootUrl.toLowerCase()) {
                return url;
            }
            if (url.indexOf('http') == 0)
                return url;
            return window["app"].rootUrl + url;
        };
        AjaxUtils.get = function (url, data, cache) {
            if (cache === void 0) { cache = false; }
            return this.ajaxQuery(url, "GET", data, cache);
        };
        AjaxUtils.getHtml = function (url, data) {
            var ajax = $.ajax({
                type: "GET",
                headers: this.getHeaders(),
                url: this.getFullUrl(url),
                data: data
            });
            ajax.fail(this.handleError);
            return ajax;
        };
        AjaxUtils.post = function (url, data, cors) {
            if (cors === void 0) { cors = false; }
            var requestData = data || {};
            return this.ajaxQuery(url, "POST", JSON.stringify(requestData), false, cors);
        };
        AjaxUtils.getHeaders = function () {
            var headers = {
                "RequestVerificationToken": $("input[name='__RequestVerificationToken']").val()
            };
            return headers;
        };
        AjaxUtils.uploadFile = function (url, formData) {
            var ajax = $.ajax({
                type: "POST",
                headers: this.getHeaders(),
                url: this.getFullUrl(url),
                dataType: "json",
                contentType: false,
                processData: false,
                data: formData || null
            });
            ajax.fail(this.handleError);
            return ajax;
        };
        AjaxUtils.getTemplate = function (templateName) {
            var ajax = $.ajax({
                type: "GET",
                url: this.getFullUrl("dist/html/templates/" + templateName + ".html?v=220925")
            });
            return ajax;
        };
        AjaxUtils.submit = function (formElement, extendedData) {
            var $form = $(formElement), formData = new FormData(formElement);
            if (extendedData) {
                for (var key in extendedData) {
                    if (extendedData.hasOwnProperty(key)) {
                        formData.set(key, extendedData[key]);
                    }
                }
            }
            return $.ajax({
                type: $form.attr("method"),
                url: $form.attr("action"),
                data: formData,
                headers: this.getHeaders(),
                cache: false,
                contentType: false,
                processData: false
            });
        };
        /**
         *
         * @param href [REQUIRED] is the URL for your CSS file.
         * @param before [OPTIONAL] is the element the script should use as a reference for injecting our stylesheet <link> before
         * By default, loadCSS attempts to inject the link after the last stylesheet or script in the DOM. However, you might desire a more specific location in your document.
         * @param media [OPTIONAL] is the media type or query of the stylesheet. By default it will be 'all'
         */
        AjaxUtils.loadCss = function (href, before, media) {
            var doc = window.document;
            var ss = doc.createElement("link");
            var ref;
            if (before) {
                ref = before;
            }
            else {
                var refs = (doc.body || doc.getElementsByTagName("head")[0]).childNodes;
                ref = refs[refs.length - 1];
            }
            var sheets = doc.styleSheets;
            ss.rel = "stylesheet";
            ss.href = this.getFullUrl(href);
            // temporarily set media to something inapplicable to ensure it'll fetch without blocking render
            ss.media = "only x";
            // wait until body is defined before injecting link. This ensures a non-blocking load in IE11.
            function ready(cb) {
                if (doc.body) {
                    return cb();
                }
                setTimeout(function () {
                    ready(cb);
                });
            }
            // Inject link
            // Note: the ternary preserves the existing behavior of "before" argument, but we could choose to change the argument to "after" in a later release and standardize on ref.nextSibling for all refs
            // Note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/
            ready(function () {
                ref.parentNode.insertBefore(ss, (before ? ref : ref.nextSibling));
            });
            // A method (exposed on return object for external use) that mimics onload by polling document.styleSheets until it includes the new sheet.
            var onloadcssdefined = function (cb) {
                var resolvedHref = ss.href;
                var i = sheets.length;
                while (i--) {
                    if (sheets[i].href === resolvedHref) {
                        return cb();
                    }
                }
                setTimeout(function () {
                    onloadcssdefined(cb);
                });
            };
            function loadCb() {
                if (ss.addEventListener) {
                    ss.removeEventListener("load", loadCb);
                }
                ss.media = media || "all";
            }
            // once loaded, set link's media back to `all` so that the stylesheet applies once it loads
            if (ss.addEventListener) {
                ss.addEventListener("load", loadCb);
            }
            ss.onloadcssdefined = onloadcssdefined;
            onloadcssdefined(loadCb);
            return ss;
        };
        ;
        return AjaxUtils;
    }());
    exports.AjaxUtils = AjaxUtils;
});



},{"jquery":214,"scriptjs":194}],45:[function(require,module,exports){
arguments[4][44][0].apply(exports,arguments)
},{"dup":44,"jquery":214,"scriptjs":194}],46:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash", "toastr", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var AuthorRewardUtils = (function () {
        function AuthorRewardUtils() {
        }
        AuthorRewardUtils.toggle = function (btn) {
            var $icon = $(btn), $btn = $icon.parent();
            if ($btn.attr("disabled"))
                return;
            $btn.attr("disabled", "disabled").addClass("is-loading");
            var $reward = $($btn.parents(".reward").get(0));
            var rewardId = $reward.attr("data-reward-id"), isHidden = $reward.attr("data-hidden") === "true";
            isHidden = !isHidden;
            ajaxUtils_1.AjaxUtils.post("authorReward/toggleTitleVisibility", {
                id: rewardId,
                isHidden: isHidden
            }).done(function (result) {
                if (result.isSuccessful) {
                    $reward.attr("data-hidden", isHidden + "");
                    var $rewardTitle = $reward.find(".reward-title");
                    if (isHidden) {
                        $rewardTitle.removeClass("text-bold").addClass("text-muted").text("Название скрыто");
                        $btn.parent().html("<span data-hint=\"Показать название награды " + ("\u00AB" + result.data.title + "\u00BB") + "\" class=\"hint-top hint-large\">\
                                                <button class=\"btn btn-default btn-sm btn-with-icon\" onclick=\"AppUtils.AuthorReward.toggle(this);\">\
                                                    <span></span>\
                                                    <i class=\"icon-eye\"></i> Показать\
                                                </button>\
                                            </span>");
                    }
                    else {
                        $rewardTitle.addClass("text-bold").removeClass("text-muted").text("\u00AB" + result.data.title + "\u00BB");
                        $btn.parent().html("<span data-hint=\"Скрыть название награды\" class=\"hint-top\">\
                                                <button class=\"btn btn-simple-danger btn-sm btn-with-icon\" onclick=\"AppUtils.AuthorReward.toggle(this);\">\
                                                    <span></span>\
                                                    <i class=\"icon-eye-slash\"></i> Скрыть\
                                                </button>\
                                            </span>");
                    }
                    toastr.success(result.messages[0]);
                }
                else if (result.isWarning) {
                    toastr.warning(result.messages[0]);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                $btn.removeAttr("disabled").removeClass("is-loading");
            });
        };
        return AuthorRewardUtils;
    }());
    _.extend(window["AppUtils"], {
        AuthorReward: AuthorRewardUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AuthorRewardUtils;
});

},{"../utils/ajaxUtils":45,"jquery":214,"lodash":216,"toastr":199}],47:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var BrowserUtils = (function () {
        function BrowserUtils() {
        }
        /**
         * Detect IE     *
         * @returns {} returns version of IE or false, if browser is not Internet Explorer
         */
        BrowserUtils.isIE = function () {
            var ua = window.navigator.userAgent;
            // Test values; Uncomment to check result …
            // IE 10
            // ua = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)';
            // IE 11
            // ua = 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko';
            // Edge 12 (Spartan)
            // ua = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0';
            // Edge 13
            // ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Safari/537.36 Edge/13.10586';
            var msie = ua.indexOf("MSIE ");
            if (msie > 0) {
                // IE 10 or older => return version number
                return parseInt(ua.substring(msie + 5, ua.indexOf(".", msie)), 10);
            }
            var trident = ua.indexOf("Trident/");
            if (trident > 0) {
                // IE 11 => return version number
                var rv = ua.indexOf("rv:");
                return parseInt(ua.substring(rv + 3, ua.indexOf(".", rv)), 10);
            }
            var edge = ua.indexOf("Edge/");
            if (edge > 0) {
                // Edge (IE 12+) => return version number
                return parseInt(ua.substring(edge + 5, ua.indexOf(".", edge)), 10);
            }
            // other browser
            return false;
        };
        BrowserUtils.isMobile = function () {
            if (this.isMobileDevice !== null)
                return this.isMobileDevice;
            var test = false; //initiate as false
            // device detection
            if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent)
                || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0, 4)))
                test = true;
            this.isMobileDevice = test;
            return test;
        };
        BrowserUtils.isMobileDevice = null;
        return BrowserUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = BrowserUtils;
});

},{}],48:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var CommentLoadUtil = (function () {
        function CommentLoadUtil() {
        }
        /** Флаг загрузки комментариев */
        CommentLoadUtil.loaded = ko.observable(false);
        return CommentLoadUtil;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CommentLoadUtil;
});

},{"knockout":191}],49:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash", "toastr", "../utils/dateTimeUtils", "../utils/ajaxUtils", "../utils/richContentUtils", "../utils/stringUtils", "../utils/imageZoomUtils", "../../app/components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var toastr = require("toastr");
    var Clipboard = require("clipboard");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var modalDialog_1 = require("../../app/components/modalDialog");
    var CommentUtils = (function () {
        function CommentUtils() {
        }
        CommentUtils.getComment = function (commentId) {
            return $("#" + commentId).siblings(".comment");
        };
        CommentUtils.toggleAsPinned = function (btn, commentId, isPinned) {
            var $btn = $(btn);
            if ($btn.attr('disabled'))
                return;
            $btn.attr('disabled', 'disabled');
            var id = parseInt(this.getComment(commentId).attr('data-id'));
            ajaxUtils_1.AjaxUtils.get('comment/toggleAsPinned', { id: id, isPinned: isPinned })
                .done(function (result) {
                if (result.isSuccessful) {
                    toastr.success(isPinned ? 'Комментарий откреплен.' : 'Комментарий закреплен.');
                    CommentUtils.reloadComments();
                }
                else {
                    alert(result.messages[0]);
                }
            })
                .always(function () {
                $btn.removeAttr('disabled');
            });
        };
        CommentUtils.toggleHide = function (btn, commentId, hide) {
            var _this = this;
            var $btn = $(btn);
            if ($btn.attr('disabled'))
                return;
            var modal = window["AppComponents"].ModalDialog;
            var messageText = hide ? "Вы действительно хотите скрыть комментарий под спойлер?<br/>Действие является необратимым." : "Вы уверены, что хотите отменить скрытие комментария?";
            modal.show({
                title: "Скрытие комментария",
                message: messageText,
                type: modalDialog_1.ModalType.Confirm,
                onSubmit: function () {
                    $btn.attr('disabled', 'disabled');
                    var $comment = _this.getComment(commentId);
                    var id = parseInt($comment.attr('data-id'));
                    ajaxUtils_1.AjaxUtils.post('comment/hide', { id: id, isHiddenByAuthor: hide })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            var $html = $(result.data.html);
                            $comment.replaceWith($html);
                            dateTimeUtils_1.default.displayTime($html);
                            imageZoomUtils_1.default.init($html);
                        }
                        else {
                            alert(result.messages[0]);
                        }
                    })
                        .always(function () {
                        $btn.removeAttr('disabled');
                        modal.hide();
                    });
                }
            });
        };
        CommentUtils.replyWithConfirm = function (commentId, rootId, rootType) {
            if (rootId === void 0) { rootId = null; }
            if (rootType === void 0) { rootType = null; }
            var form = this.getForm(rootId, rootType);
            if (form.isTextChange) {
                form.showConfirmModal(this.reply.bind(this, commentId, rootId, rootType));
            }
            else {
                this.reply(commentId, rootId, rootType);
            }
        };
        CommentUtils.reply = function (commentId, rootId, rootType) {
            var _this = this;
            if (rootId === void 0) { rootId = null; }
            if (rootType === void 0) { rootType = null; }
            if (this.onCancelEditing) {
                this.onCancelEditing();
            }
            if (this.onCancelReply) {
                this.onCancelReply();
            }
            var $comment = this.getComment(commentId), id = parseInt($comment.attr("data-id")), threadId = parseInt($comment.attr("data-thread")), level = parseInt($comment.attr("data-level")), isIgnored = $comment.attr("data-is-ignored") === "true";
            $("comment-form-v1").appendTo($comment.find(".reply-placeholder"));
            var commendData = {
                id: null,
                parentId: id,
                threadId: threadId,
                level: level + 1,
                text: "",
                isIgnored: isIgnored,
                isPinned: false
            };
            var form = this.getForm(rootId, rootType);
            form.startCreating(commendData, function (data) {
                _this.restoreRootReply();
                var $html = $(_this.collapsingAreaHtml + data.html);
                $comment.siblings(".replies").prepend($html);
                dateTimeUtils_1.default.displayTime($html);
                _this.reInitNewComments($html);
                $comment.removeClass("c-reply");
                var $wrapper = $comment.parent();
                if (!$wrapper.hasClass("expanded-replies") &&
                    !$wrapper.hasClass("collapsed-replies")) {
                    $wrapper.addClass("expanded-replies");
                    $wrapper.find(".replies-count").html("1");
                }
                imageZoomUtils_1.default.init($html);
            });
            $comment.addClass("c-reply");
            $(".edit-reply textarea").froalaEditor("events.focus");
            this.onCancelReply = function () {
                $comment.removeClass("c-reply");
                form.cancel();
            };
        };
        CommentUtils.edit = function (commentId, rootId, rootType) {
            var _this = this;
            if (rootId === void 0) { rootId = null; }
            if (rootType === void 0) { rootType = null; }
            if (this.onCancelEditing) {
                this.onCancelEditing();
            }
            if (this.onCancelReply) {
                this.onCancelReply();
            }
            var $comment = this.getComment(commentId), id = parseInt($comment.attr("data-id")), isIgnored = $comment.attr("data-is-ignored") === "true", isPinned = $comment.attr("data-is-pinned") === "true";
            var $textContainer = $comment.find("article"), currentText = $comment.find("article").html(), originalText = $comment.find(".rich-content").html();
            originalText = richContentUtils_1.default.richTextToFroala(originalText);
            var isRm = $textContainer.attr('id') && $textContainer.attr('id').indexOf('rmjs') != -1;
            var tmpRmContainerHeight = $textContainer.css('height');
            if (isRm) {
                $textContainer.css('height', '');
                $comment.find("[data-readmore-toggle='']").hide();
            }
            function returnLongCommentToOriginState() {
                if (!isRm) {
                    return;
                }
                $textContainer.css('height', tmpRmContainerHeight);
                $comment.find("[data-readmore-toggle='']").show();
            }
            this.onCancelEditing = function () {
                _this.restoreRootReply();
                $textContainer.html(currentText);
                $comment.removeClass("c-editing").addClass("c-view");
                returnLongCommentToOriginState();
            };
            $textContainer.empty();
            $("comment-form-v1").appendTo($textContainer);
            var commendData = {
                id: id,
                text: originalText,
                isIgnored: isIgnored,
                isPinned: isPinned
            };
            function replaceCommentMarkup(html) {
                var $html = $(html);
                $comment.replaceWith($html);
                dateTimeUtils_1.default.displayTime($html);
                imageZoomUtils_1.default.init($html);
            }
            this.getForm(rootId, rootType).startEditing(commendData, function (data) {
                _this.restoreRootReply();
                replaceCommentMarkup(data.html);
            }, this.onCancelEditing, function (data) {
                _this.restoreRootReply();
                if (data.fullDelete) {
                    var $wrapper = $comment.parent();
                    var $replies = $wrapper.parent(".replies");
                    if ($replies.find(".comment").length === 1) {
                        $replies.parent()
                            .removeClass("expanded-replies")
                            .removeClass("collapsed-replies");
                    }
                    $wrapper.remove();
                }
                else if (data.isReload) {
                    CommentUtils.reloadComments();
                }
                else {
                    replaceCommentMarkup(data.html);
                }
            });
            $comment.removeClass("c-view").addClass("c-editing");
        };
        CommentUtils.cancel = function (commentId) {
            var $comment = this.getComment(commentId);
            var form = this.getForm(null, null);
            form.cancel();
            this.restoreRootReply();
            $comment.removeClass("c-reply");
        };
        CommentUtils.showHidden = function (commentId) {
            var $comment = this.getComment(commentId);
            var $toggle = $comment.find(".comment-hidden-toggle");
            var hiddenComment = $comment.find(".hidden-content");
            if ($toggle.data("commentVisible") && $toggle.data("commentVisible") === true) {
                $toggle.text("показать комментарий");
                hiddenComment.hide();
                $toggle.data("commentVisible", false);
            }
            else {
                $toggle.text("скрыть комментарий");
                hiddenComment.show();
                $toggle.data("commentVisible", true);
            }
        };
        CommentUtils.getForm = function (rootId, rootType) {
            var form = window["AppComponents"].CommentFormV1;
            if (rootId && rootType) {
                form.rootId = rootId;
                form.rootType = rootType;
            }
            return form;
        };
        CommentUtils.restoreRootReply = function () {
            $("comment-form-v1").appendTo(document.getElementById("root-reply-placeholder"));
        };
        CommentUtils.vote = function (btn, commentId, vote) {
            var $icon = $(btn), $btn = $icon.parent();
            if ($btn.attr("disabled"))
                return;
            $btn.attr("disabled", "disabled");
            var toggleClass = "toggle", $comment = $("#" + commentId).siblings(".comment"), id = parseInt($comment.attr("data-id")), $rating = $comment.find(".comment-rating-count"), voteId = $rating.attr("data-vote-id");
            if (!$icon.hasClass(toggleClass)) {
                $btn.addClass("animate");
                setTimeout(function () {
                    $btn.removeClass("animate");
                }, 500);
            }
            ajaxUtils_1.AjaxUtils.post("comment/vote", {
                voteId: voteId,
                targetId: id,
                isLiked: $icon.hasClass(toggleClass) ? null : vote === 1
            }).done(function (result) {
                if (result.isSuccessful) {
                    $rating.html(result.data.rating);
                    $rating.attr("data-vote-id", result.data.voteId);
                    if ($icon.hasClass(toggleClass)) {
                        $icon.removeClass(toggleClass);
                        $icon.addClass("hover-state-canceled");
                        $icon.on("mouseleave", function () {
                            $icon.removeClass("hover-state-canceled");
                            $icon.off("mouseleave");
                        });
                    }
                    else {
                        $comment.find(".like, .dislike").removeClass(toggleClass);
                        $icon.addClass(toggleClass);
                    }
                }
                else if (result.isWarning) {
                    toastr.warning(result.messages[0]);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                $btn.removeAttr("disabled");
            });
        };
        CommentUtils.expand = function (element, parentId, rootId, rootType) {
            var _this = this;
            var $el = $(element);
            var state = $el.attr("data-state") || "none";
            if (state === "loading") {
                return;
            }
            if (state === "loaded") {
                $el.parent().removeClass("collapsed-replies").addClass("expanded-replies");
                return;
            }
            $el.attr("data-state", "loading");
            $el.find(".toggle-text").text("загрузка...");
            $el.find("i:first").removeClass("icon-plus-square-o").addClass("icon-spinner icon-spin-animate");
            var sorting = stringUtils_1.default.getParam("sorting");
            ajaxUtils_1.AjaxUtils.get("comment/loadThread", {
                parentId: parentId,
                rootId: rootId,
                rootType: rootType,
                lastViewTime: this.lastViewTime,
                sorting: sorting
            })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    $el.attr("data-state", "none");
                    $el.find(".toggle-text").text("раскрыть ветку");
                    $el.find("i:first").removeClass("icon-spinner icon-spin-animate").addClass("icon-plus-square-o");
                    return;
                }
                $el.siblings(".replies").html(_this.collapsingAreaHtml + result.data.html);
                var $replies = $el.siblings(".replies");
                dateTimeUtils_1.default.displayTime($replies);
                richContentUtils_1.default.processHtml($replies);
                $el.find("i:first").removeClass("icon-spinner icon-spin-animate").addClass("icon-plus-square-o");
                $el.find(".toggle-text").text("раскрыть ветку");
                $el.parent().removeClass("collapsed-replies")
                    .removeClass("is-new")
                    .addClass("expanded-replies");
                _this.reInitNewComments($replies);
                imageZoomUtils_1.default.init($replies);
                $el.attr("data-state", "loaded");
                _this.initVotesInfo($replies);
            });
        };
        CommentUtils.loadMore = function (btn, soring, rootId, rootType) {
            var _this = this;
            var $btn = $(btn);
            if ($btn.attr("disabled"))
                return;
            var lastCommentId = $btn.attr("data-last-id");
            $btn.attr("disabled", "disabled");
            var $icon = $btn.find("i");
            $icon.addClass("icon-spin-animate");
            ajaxUtils_1.AjaxUtils.get("comment/loadMore", {
                sorting: soring,
                lastCommentId: lastCommentId,
                rootId: rootId,
                rootType: rootType,
                lastViewTime: this.lastViewTime
            }).done(function (result) {
                if (result.isSuccessful) {
                    $btn.attr("data-last-id", result.data.lastCommentId);
                    var $html = $(_this.collapsingAreaHtml + result.data.html);
                    $(".comments").append($html);
                    $(".pagination-container").hide();
                    $("#notLoadedComments")
                        .text(result.data.notLoaded +
                        " " +
                        stringUtils_1.default.pluralize(result.data.notLoaded, ["комментарий", "комментария", "комментариев"]));
                    if (result.data.new > 0) {
                        $("#newNotLoadedComments").show();
                        $("#newNotLoadedComments")
                            .text("+" + " " + result.data.new + " " +
                            stringUtils_1.default.pluralize(result.data.new, ["новый", "новых", "новых"]));
                    }
                    else {
                        $btn.removeClass("is-new");
                        $("#newNotLoadedComments").hide();
                    }
                    dateTimeUtils_1.default.displayTime($html);
                    richContentUtils_1.default.processHtml($html);
                    _this.reInitNewComments($html);
                    if (result.data.more) {
                        $icon.removeClass("icon-spin-animate");
                    }
                    else {
                        $btn.hide();
                    }
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                $btn.removeAttr("disabled");
            });
        };
        CommentUtils.scrollToParent = function (parentAnchor) {
            var $anchor = $(parentAnchor), $comment = $anchor.siblings(".comment");
            $comment.addClass("highlighted");
            setTimeout(function () {
                $comment.removeClass("highlighted");
            }, 500);
            $("html,body").animate({ scrollTop: $anchor.offset().top }, 400);
        };
        CommentUtils.reInitNewComments = function ($container) {
            if (!$container) {
                $container = $(".comments");
            }
            this.$newElements = $(".is-new");
            if (this.$newElements.length) {
                $("#comments-navigation").show();
                $("#comments-navigation .new").text(this.$newElements.length);
            }
            $container.find(".comment-toggle-collapse").each(function (index, el) {
                $(el).on("click", function () { return $(el).parent().removeClass("expanded-replies").addClass("collapsed-replies"); });
            });
            $container.find(".comment-collapsing-area").each(function (index, el) {
                var $commetWrapper = $(el).parent().parent(); // пробуем найти .comment-wrapper
                if ($commetWrapper.is(".comments-new-line")) {
                    $commetWrapper = $commetWrapper.parent();
                }
                $(el)
                    .on("click", function () { return $commetWrapper.removeClass("expanded-replies").addClass("collapsed-replies"); })
                    .on("mouseenter", function () { return $commetWrapper.addClass("collapsing-area-hovered"); })
                    .on("mouseleave", function () { return $commetWrapper.removeClass("collapsing-area-hovered"); });
            });
            if (this.clipboard) {
                this.clipboard.destroy();
            }
            this.clipboard = new Clipboard(".comment-url", {
                text: function (el) { return location.origin + $(el).attr("data-clipboard"); }
            });
            this.clipboard.off("sucess");
            this.clipboard.on("success", function (e) {
                var $el = $(e.trigger);
                $el.attr("data-hint-prev", $el.attr("data-hint"))
                    .attr("data-hint", "Ссылка скопирована")
                    .addClass("hint-always");
                setTimeout(function () {
                    $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                }, 3000);
            });
            this.clipboard.on("error", function (e) {
                var $el = $(e.trigger);
                var url = location.origin + $el.attr("data-clipboard");
                prompt("Чтобы скопировать ссылку на комментарий, нажмите Ctrl+C и потом Enter.", url);
            });
        };
        CommentUtils.init = function (lastViewTime) {
            var _this = this;
            this.lastViewTime = lastViewTime;
            $(document).ready(function () {
                _this.reInitNewComments();
                var $highlighted = $(".highlighted");
                if ($highlighted[0]) {
                    setTimeout(function () {
                        _this.scrollToNew($highlighted);
                    }, 50);
                }
                if (_this.$newElements.length) {
                    // Скролл к первому комментарию
                    if (window.location.hash === "#first_unread" && $highlighted.length === 0) {
                        _this.scrollToNew(_this.$newElements.first());
                    }
                    var currentIndex = -1;
                    var navigate = function () {
                        if (currentIndex === $(".is-new").length) {
                            currentIndex = 0;
                        }
                        if (currentIndex < 0) {
                            currentIndex = _this.$newElements.length - 1;
                        }
                        _this.scrollToNew($(".is-new").get(currentIndex));
                    };
                    $("#comments-navigation .prev-new").on("click", function (e) {
                        currentIndex--;
                        navigate();
                        e.preventDefault();
                    });
                    $("#comments-navigation .next-new").on("click", function (e) {
                        currentIndex++;
                        navigate();
                        e.preventDefault();
                    });
                    $(document).keydown(function (e) {
                        var $target = $(e.target);
                        if ($target.hasClass("fr-element")
                            || $target.parents(".fr-element")[0]
                            || $target.is("textarea")
                            || $target.is("input")) {
                            return;
                        }
                        switch (e.which) {
                            case 65:
                                currentIndex--;
                                navigate();
                                break;
                            case 68:
                                currentIndex++;
                                navigate();
                                break;
                            default: return; // exit this handler for other keys
                        }
                        //e.preventDefault(); // prevent the default action (scroll / move caret)
                    });
                }
                if ($(".comments").height() > 1000) {
                    $(".btn-bottom-comment").show().on("click", function () {
                        $("html,body").animate({ scrollTop: $("#comments").offset().top }, 350);
                        setTimeout(function () {
                            $(".edit-reply textarea").froalaEditor("events.focus");
                        }, 400);
                    });
                }
            });
        };
        CommentUtils.initVotesInfo = function (el) {
            if (el === void 0) { el = null; }
            if (!el) {
                el = $(".comments");
            }
            el.find(".dropdown-toggle").on("click", function (e) {
                var container = $(e.target).parent();
                var commentId = container.attr("data-comment-id");
                var spinner = container.find(".widget-spinner").parent();
                if (spinner.length == 0) {
                    return;
                }
                spinner.show();
                ajaxUtils_1.AjaxUtils.get("comment/getVotes", { id: commentId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    container.find(".dropdown-menu").html(result.data.html);
                    dateTimeUtils_1.default.displayTime(container);
                })
                    .always(function () {
                    spinner.hide();
                });
            });
        };
        CommentUtils.scrollToNew = function (el) {
            var $el = $(el);
            var $anchor, $toHighlight;
            if ($el.is(".comment")) {
                $toHighlight = $el;
                $el.parent()
                    .parentsUntil(".comments", ".collapsed-replies")
                    .removeClass("collapsed-replies")
                    .addClass("expanded-replies");
                $anchor = $el.siblings(".anchor");
            }
            else if ($el.is(".load-more-comments")) {
                $toHighlight = $el;
                $anchor = $el;
            }
            else {
                $toHighlight = $el.find(".comment-toggle-expand");
                $anchor = $el.find(".anchor");
            }
            if (!$toHighlight.is(".highlighted")) {
                $toHighlight.addClass("highlighted");
                setTimeout(function () {
                    $toHighlight.removeClass("highlighted");
                }, 500);
            }
            $("html,body").animate({ scrollTop: $anchor.offset().top }, { duration: 400, queue: false });
        };
        CommentUtils.reloadComments = function () {
            $.pjax.reload("#pjax-container");
        };
        CommentUtils.collapsingAreaHtml = "<div class='comment-collapsing-area'></div>";
        CommentUtils.clipboard = null;
        return CommentUtils;
    }());
    _.extend(window["AppUtils"], {
        Comment: CommentUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CommentUtils;
});



},{"../../app/components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../utils/imageZoomUtils":57,"../utils/richContentUtils":67,"../utils/stringUtils":69,"clipboard":202,"jquery":214,"lodash":216,"toastr":199}],50:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "lodash", "js.cookie"], factory);
    }
})(function (require, exports) {
    "use strict";
    var _ = require("lodash");
    var Cookies = require("js.cookie");
    var CookieConsentUtils = (function () {
        function CookieConsentUtils() {
        }
        CookieConsentUtils.init = function () {
            if (app.isAuthenticated || Cookies.get("CookieConsent") == "Accepted")
                return;
            document.addEventListener("DOMContentLoaded", function () {
                var cookieConsent = document.getElementById("cookieConsent");
                var acceptCookie = document.getElementById("acceptCookie");
                cookieConsent.style.display = "flex";
                acceptCookie.addEventListener("click", function () {
                    var date = new Date();
                    date.setFullYear(date.getFullYear() + 1);
                    Cookies.set("CookieConsent", "Accepted", { expires: date });
                    cookieConsent.style.display = "none";
                });
            });
        };
        return CookieConsentUtils;
    }());
    _.extend(window["AppUtils"], {
        CookieConsent: CookieConsentUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CookieConsentUtils;
});

},{"js.cookie":215,"lodash":216}],51:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "js.cookie"], factory);
    }
})(function (require, exports) {
    "use strict";
    var Cookies = require("js.cookie");
    var CookieUtils = (function () {
        function CookieUtils() {
        }
        CookieUtils.setAdultUser = function (value) {
            if (value === void 0) { value = true; }
            var date = new Date();
            date.setDate(date.getDate() + 1);
            date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
            Cookies.set("AdultUser", value, { "expires": date });
        };
        CookieUtils.getAdultUser = function () {
            return Cookies.get("AdultUser");
        };
        return CookieUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CookieUtils;
});



},{"js.cookie":215}],52:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash", "moment"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var moment = require("moment");
    var DateTimeUtils = (function () {
        function DateTimeUtils() {
        }
        DateTimeUtils.displayTime = function ($container) {
            if ($container === void 0) { $container = null; }
            var $items;
            if (_.isElement($container)) {
                $items = $container.find("span[data-time]");
            }
            else {
                $items = $("span[data-time]");
            }
            $items.each(function (index, el) {
                var $el = $(el), value = $el.attr("data-time"), format = $el.attr("data-format"), showOnlyHint = $el.attr("data-only-hint");
                var time = moment(value, moment.ISO_8601, true);
                var formattedText;
                if (format === undefined || format === null || format.indexOf("calendar") !== -1) {
                    formattedText = DateTimeUtils.formatCalendar(time, format);
                }
                else if (format === "from-now") {
                    formattedText = time.fromNow();
                }
                else {
                    formattedText = time.format(format);
                }
                var currentTite = $el.attr("data-hint") || "";
                var formattedTextTitle = time.format("D MMMM YYYY в HH:mm:ss");
                if (currentTite.indexOf(formattedTextTitle) === -1) {
                    $el.attr("data-hint", currentTite + formattedTextTitle);
                }
                if (showOnlyHint) {
                    return;
                }
                var initialHtml = $el.html();
                if (initialHtml.indexOf(formattedText) === -1) {
                    $el.html(initialHtml + formattedText);
                }
            });
        };
        DateTimeUtils.formatCalendar = function (time, format) {
            if (!time.isValid())
                return "";
            if (format === "calendar-xs") {
                if (time.year() !== moment().year()) {
                    return time.format("D.MM.YY");
                }
                return time.calendar(null, {
                    sameDay: "HH:mm",
                    lastDay: "вчера",
                    lastWeek: "D MMM",
                    sameElse: "D MMM"
                });
            }
            if (format === "calendar-sm") {
                if (time.year() !== moment().year()) {
                    return time.format("D.MM.YY[<br/>]HH:mm");
                }
                return time.calendar(null, {
                    sameDay: "HH:mm",
                    lastDay: "вчера[<br/>]HH:mm",
                    lastWeek: "D MMM[<br/>]HH:mm",
                    sameElse: "D MMM[<br/>]HH:mm"
                });
            }
            var formattedText;
            if (time.year() !== moment().year()) {
                return time.format(this.defaultFormat);
            }
            if (format === "calendar-short") {
                formattedText = time.calendar(null, {
                    sameDay: "сегодня в HH:mm",
                    lastDay: "вчера в HH:mm",
                    lastWeek: "D MMMM",
                    sameElse: "D MMMM"
                });
            }
            else {
                formattedText = time.calendar(null, {
                    sameDay: "сегодня в HH:mm",
                    lastDay: "вчера в HH:mm",
                    lastWeek: "D MMMM в HH:mm",
                    nextDay: "[завтра в] HH:mm",
                    nextWeek: "D MMMM в HH:mm",
                    sameElse: "D MMMM в HH:mm"
                });
            }
            return formattedText;
        };
        DateTimeUtils.defaultFormat = "D MMMM YYYY";
        return DateTimeUtils;
    }());
    _.extend(window["AppUtils"], {
        DateTime: DateTimeUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = DateTimeUtils;
});

},{"jquery":214,"lodash":216,"moment":219}],53:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var DevTools = (function () {
        function DevTools() {
        }
        DevTools.init = function (devToolsCallback, clearConsole, delay) {
            if (delay === void 0) { delay = 500; }
            try {
                var open = false;
                var threshold = 160;
                var timer = setInterval(function () {
                    try {
                        if (clearConsole) {
                            console.clear();
                        }
                        var widthThreshold = window.outerWidth - window.innerWidth > threshold;
                        var heightThreshold = window.outerHeight - window.innerHeight > threshold;
                        if (!(heightThreshold && widthThreshold) &&
                            ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) || widthThreshold || heightThreshold)) {
                            if (!open) {
                                devToolsCallback();
                                if (!clearConsole) {
                                    clearInterval(timer);
                                }
                            }
                            open = true;
                        }
                        else {
                            open = false;
                        }
                    }
                    catch (ex) {
                        console.error(ex);
                        clearInterval(timer);
                    }
                }, delay);
            }
            catch (ex) {
                console.error(ex);
            }
        };
        return DevTools;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = DevTools;
});

},{}],54:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "lodash", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var _ = require("lodash");
    var $ = require("jquery");
    /** Утилита для экспорта книг */
    var ExportBookUtils = (function () {
        function ExportBookUtils() {
        }
        /**
         * Скачивает файл книги
         * @param id - идентификатор работы
         * @param type - формат книги
         * @param trial - флаг для ознакомления
         * @param fileName - название файла
         */
        ExportBookUtils.download = function (id, type, trial, fileName) {
            if (!window.URL.createObjectURL) {
                throw new Error('createObjectURL is not supported!');
            }
            var btn = $("#btn-download");
            var spinner = $("#spinner");
            btn.hide();
            spinner.show();
            var req = new XMLHttpRequest();
            req.open("GET", this.getFullUrl("work/download?id=" + id + "&type=" + type + "&trial=" + trial), true);
            req.responseType = "blob";
            req.onload = function (event) {
                spinner.hide();
                btn.show();
                var blob = req.response;
                if (blob.size === 0) {
                    alert("Ошибка скачивания!");
                    return;
                }
                var link = document.createElement('a');
                link.href = window.URL.createObjectURL(blob);
                type = type === "fb2" ? "fb2.zip" : type;
                link.download = fileName + "." + type;
                link.click();
            };
            req.send();
        };
        /** Формирует полный урл к api */
        ExportBookUtils.getFullUrl = function (url) {
            if (url.substring(0, window["app"].rootUrl.length).toLowerCase() === window["app"].rootUrl.toLowerCase()) {
                return url;
            }
            return window["app"].rootUrl + url;
        };
        return ExportBookUtils;
    }());
    _.extend(window["AppUtils"], {
        ExportBook: ExportBookUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ExportBookUtils;
});

},{"jquery":214,"lodash":216}],55:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var Clipboard = require("clipboard");
    var GiftCodeUtils = (function () {
        function GiftCodeUtils() {
        }
        GiftCodeUtils.init = function () {
            var _this = this;
            $(document).ready(function () {
                if (_this.clipboard) {
                    _this.clipboard.destroy();
                }
                if (_this.clipboardShare) {
                    _this.clipboardShare.destroy();
                }
                _this.clipboard = new Clipboard(".gift-code-to-copy", {
                    text: function (el) { return $(el).attr("data-clipboard"); }
                });
                _this.clipboardShare = new Clipboard(".btn-share-gift", {
                    text: function (el) { return $(el).attr("data-clipboard"); }
                });
                _this.clipboard
                    .off("sucess")
                    .on("success", function (e) {
                    var $el = $(e.trigger);
                    $el.attr("data-hint-prev", $el.attr("data-hint"))
                        .attr("data-hint", "Подарочный код скопирован")
                        .addClass("hint-always");
                    setTimeout(function () {
                        $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                    }, 3000);
                })
                    .on("error", function (e) {
                    var $el = $(e.trigger);
                    var url = $el.attr("data-clipboard");
                    prompt("Чтобы скопировать подарочный код, нажмите Ctrl+C и потом Enter.", url);
                });
                _this.clipboardShare
                    .off("sucess")
                    .on("success", function (e) {
                    var $el = $(e.trigger);
                    $el.attr("data-hint-prev", $el.attr("data-hint"))
                        .attr("data-hint", "Сообщение скопировано")
                        .addClass("hint-always");
                    setTimeout(function () {
                        $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                    }, 3000);
                })
                    .on("error", function (e) {
                    var $el = $(e.trigger);
                    var url = $el.attr("data-clipboard");
                    prompt("Чтобы скопировать сообщение, нажмите Ctrl+C и потом Enter.", url);
                });
            });
        };
        GiftCodeUtils.clipboard = null;
        GiftCodeUtils.clipboardShare = null;
        return GiftCodeUtils;
    }());
    _.extend(window["AppUtils"], {
        GiftCodes: GiftCodeUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = GiftCodeUtils;
});

},{"clipboard":202,"jquery":214,"lodash":216}],56:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ImageUtils = (function () {
        function ImageUtils() {
        }
        ImageUtils.getImageSize = function (url) {
            var deferred = $.Deferred(), image = new Image();
            image.onload = function () {
                var size = {
                    width: image.width,
                    height: image.height
                };
                deferred.resolve(size);
            };
            image.src = url;
            return deferred.promise();
        };
        ImageUtils.createDropZone = function ($el, onDrop) {
            var lastenter;
            $el.on({
                dragover: function (event) {
                    event.preventDefault();
                    event["dataTransfer"].dropEffect = "copy";
                },
                dragenter: function (event) {
                    lastenter = event.target;
                    $el.addClass("over");
                },
                dragleave: function (event) {
                    if (lastenter === event.target) {
                        $el.removeClass("over");
                    }
                },
                drop: function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                    $el.removeClass("over");
                    var files = event["dataTransfer"].files;
                    if (onDrop) {
                        onDrop(files);
                    }
                }
            });
        };
        return ImageUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ImageUtils;
});

},{"jquery":214}],57:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ImageZoomMode;
    (function (ImageZoomMode) {
        ImageZoomMode[ImageZoomMode["PhotoSwipe"] = 1] = "PhotoSwipe";
        ImageZoomMode[ImageZoomMode["NativeApp"] = 2] = "NativeApp";
    })(ImageZoomMode || (ImageZoomMode = {}));
    var ImageZoomUtils = (function () {
        function ImageZoomUtils() {
        }
        ImageZoomUtils.setNativeAppMode = function (appMobileHandler) {
            this.zoomMode = ImageZoomMode.NativeApp;
            this.appMobileHandler = appMobileHandler;
        };
        ImageZoomUtils.init = function (rootEl) {
            var _this = this;
            if (!rootEl)
                rootEl = window.document;
            $(rootEl).find("[image-zoom]").each(function (index, el) {
                var $el = $(el);
                var $images = $el.find("img[data-width][data-height]").not("a img");
                if ($images.length === 0)
                    return;
                // Отображать картинки в галерее, с возможностью листания
                var gallery = !!$el.attr("image-zoom");
                var items = [];
                $images.each(function (i, img) {
                    var $img = $(img);
                    var src = $(img).attr("data-src-orig") ||
                        $img.attr("data-src") ||
                        $img.attr("src");
                    if (src && src.indexOf("?") > 0 && src.indexOf(window.location.hostname) > 0) {
                        src = src.split("?")[0];
                    }
                    if (_this.zoomMode === ImageZoomMode.PhotoSwipe) {
                        var item = {
                            src: src,
                            w: $img.attr("data-width"),
                            h: $img.attr("data-height")
                        };
                        items.push(item);
                    }
                    else {
                        items.push(src);
                    }
                });
                var self = _this;
                $images.each(function (index, img) {
                    $(img).on("click", function (event) {
                        event.preventDefault();
                        event.stopPropagation();
                        var options = {
                            index: index,
                            bgOpacity: 0.7,
                            arrowEl: gallery,
                            history: true,
                            getThumbBoundsFn: function () { return _this.getThumbBounds(img); }
                        };
                        if (_this.zoomMode === ImageZoomMode.PhotoSwipe) {
                            self.photoSwipe = new PhotoSwipe($(".pswp")[0], PhotoSwipeUI_Default, items, options);
                            self.photoSwipe.init();
                        }
                        else {
                            try {
                                _this.appMobileHandler.nativeImageZoom(index, items);
                            }
                            catch (ex) {
                                console.error("Image zoom error: ", ex);
                            }
                        }
                    });
                });
            });
        };
        /*
         * Инициализация дом материалов к книге
         */
        ImageZoomUtils.initWorkMaterials = function () {
            var $figures = $("#masonry figure");
            if (!$figures[0] || this.zoomMode !== ImageZoomMode.PhotoSwipe)
                return;
            var items = [];
            $figures.each(function (i, el) {
                var $link = $(el).find("a");
                var item = {
                    src: $link.attr("href"),
                    w: $link.data("width"),
                    h: $link.data("height"),
                    title: $(el).find("figcaption").text()
                };
                items.push(item);
            });
            var pswp = $(".pswp")[0];
            var self = this;
            $figures.off("click");
            $figures.on("click", function (event) {
                event.preventDefault();
                event.stopPropagation();
                var index = $figures.index($(this));
                var options = {
                    index: index,
                    bgOpacity: 0.7,
                    history: true,
                    showHideOpacity: true
                };
                // Initialize PhotoSwipe
                self.photoSwipe = new PhotoSwipe(pswp, PhotoSwipeUI_Default, items, options);
                self.photoSwipe.init();
            });
        };
        ImageZoomUtils.photoSwipe = null;
        ImageZoomUtils.zoomMode = ImageZoomMode.PhotoSwipe;
        ImageZoomUtils.getThumbBounds = function (img) {
            var pageYScroll = window.pageYOffset || document.documentElement.scrollTop;
            var rect = img.getBoundingClientRect();
            return { x: rect.left, y: rect.top + pageYScroll, w: rect.width };
        };
        return ImageZoomUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ImageZoomUtils;
});



},{"jquery":214}],58:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var Dexie = require('dexie').default;
    var DexieDb = (function () {
        function DexieDb() {
            try {
                this.db = new Dexie('author.today');
                this.db.version(1).stores({
                    readingProgress: '++id, [userId+workId], chapterId, chapterProgress, workProgress, sessionId',
                });
            }
            catch (e) {
                console.log(e);
            }
        }
        return DexieDb;
    }());
    exports.DexieDb = DexieDb;
    exports.IndexedDb = new DexieDb();
});

},{"dexie":206}],59:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    // Store.js
    var store = {}, win = window, doc = win.document, localStorageName = 'localStorage', scriptTag = 'script', storage;
    store.disabled = false;
    store.version = '1.3.20';
    store.set = function (key, value) { };
    store.get = function (key, defaultVal) { };
    store.has = function (key) { return store.get(key) !== undefined; };
    store.remove = function (key) { };
    store.clear = function () { };
    store.transact = function (key, defaultVal, transactionFn) {
        if (transactionFn == null) {
            transactionFn = defaultVal;
            defaultVal = null;
        }
        if (defaultVal == null) {
            defaultVal = {};
        }
        var val = store.get(key, defaultVal);
        var ret = transactionFn(val);
        store.set(key, ret === undefined ? val : ret);
    };
    store.getAll = function () {
        var ret = {};
        store.forEach(function (key, val) {
            ret[key] = val;
        });
        return ret;
    };
    store.forEach = function () { };
    store.serialize = function (value) { return JSON.stringify(value); };
    store.deserialize = function (value) {
        if (typeof value != 'string') {
            return undefined;
        }
        try {
            return JSON.parse(value);
        }
        catch (e) {
            return value || undefined;
        }
    };
    // Functions to encapsulate questionable FireFox 3.6.13 behavior
    // when about.config::dom.storage.enabled === false
    // See https://github.com/marcuswestin/store.js/issues#issue/13
    function isLocalStorageNameSupported() {
        try {
            return (localStorageName in win && win[localStorageName]);
        }
        catch (err) {
            return false;
        }
    }
    if (isLocalStorageNameSupported()) {
        storage = win[localStorageName];
        store.set = function (key, val) {
            if (val === undefined) {
                return store.remove(key);
            }
            storage.setItem(key, store.serialize(val));
            return val;
        };
        store.get = function (key, defaultVal) {
            var val = store.deserialize(storage.getItem(key));
            return (val === undefined ? defaultVal : val);
        };
        store.remove = function (key) { storage.removeItem(key); };
        store.clear = function () { storage.clear(); };
        store.forEach = function (callback) {
            for (var i = 0; i < storage.length; i++) {
                var key = storage.key(i);
                callback(key, store.get(key));
            }
        };
    }
    else if (doc && doc.documentElement["addBehavior"]) {
        var storageOwner, storageContainer;
        // Since #userData storage applies only to specific paths, we need to
        // somehow link our data to a specific path.  We choose /favicon.ico
        // as a pretty safe option, since all browsers already make a request to
        // this URL anyway and being a 404 will not hurt us here.  We wrap an
        // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
        // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
        // since the iframe access rules appear to allow direct access and
        // manipulation of the document element, even for a 404 page.  This
        // document can be used instead of the current document (which would
        // have been limited to the current path) to perform #userData storage.
        try {
            storageContainer = new ActiveXObject('htmlfile');
            storageContainer.open();
            storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
            storageContainer.close();
            storageOwner = storageContainer.w.frames[0].document;
            storage = storageOwner.createElement('div');
        }
        catch (e) {
            // somehow ActiveXObject instantiation failed (perhaps some special
            // security settings or otherwse), fall back to per-path storage
            storage = doc.createElement('div');
            storageOwner = doc.body;
        }
        var withIEStorage = function (storeFunction) { return function () {
            var args = Array.prototype.slice.call(arguments, 0);
            args.unshift(storage);
            // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
            // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
            storageOwner.appendChild(storage);
            storage.addBehavior('#default#userData');
            storage.load(localStorageName);
            var result = storeFunction.apply(store, args);
            storageOwner.removeChild(storage);
            return result;
        }; };
        // In IE7, keys cannot start with a digit or contain certain chars.
        // See https://github.com/marcuswestin/store.js/issues/40
        // See https://github.com/marcuswestin/store.js/issues/83
        var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
        var ieKeyFix = function (key) { return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___'); };
        store.set = withIEStorage(function (storage, key, val) {
            key = ieKeyFix(key);
            if (val === undefined) {
                return store.remove(key);
            }
            storage.setAttribute(key, store.serialize(val));
            storage.save(localStorageName);
            return val;
        });
        store.get = withIEStorage(function (storage, key, defaultVal) {
            key = ieKeyFix(key);
            var val = store.deserialize(storage.getAttribute(key));
            return (val === undefined ? defaultVal : val);
        });
        store.remove = withIEStorage(function (storage, key) {
            key = ieKeyFix(key);
            storage.removeAttribute(key);
            storage.save(localStorageName);
        });
        store.clear = withIEStorage(function (storage) {
            var attributes = storage.XMLDocument.documentElement.attributes;
            storage.load(localStorageName);
            for (var i = attributes.length - 1; i >= 0; i--) {
                storage.removeAttribute(attributes[i].name);
            }
            storage.save(localStorageName);
        });
        store.forEach = withIEStorage(function (storage, callback) {
            var attributes = storage.XMLDocument.documentElement.attributes;
            for (var i = 0, attr; attr = attributes[i]; ++i) {
                callback(attr.name, store.deserialize(storage.getAttribute(attr.name)));
            }
        });
    }
    try {
        var testKey = '__storejs__';
        store.set(testKey, testKey);
        if (store.get(testKey) != testKey) {
            store.disabled = true;
        }
        store.remove(testKey);
    }
    catch (e) {
        store.disabled = true;
    }
    store.enabled = !store.disabled;
    var LocalStorageUtils = (function () {
        function LocalStorageUtils() {
        }
        LocalStorageUtils.get = function (key) {
            try {
                var data = store.get(this.prefix + key);
                if (data === undefined || data === null) {
                    return null;
                }
                return JSON.parse(data);
            }
            catch (ex) {
                console.error(ex);
            }
            return null;
        };
        LocalStorageUtils.set = function (key, value) {
            try {
                store.set(this.prefix + key, JSON.stringify(value));
            }
            catch (ex) {
                console.error(ex);
            }
        };
        LocalStorageUtils.addToList = function (key, value, maxLength) {
            if (maxLength === void 0) { maxLength = 20; }
            try {
                var data = store.get(this.prefix + key);
                if (data === undefined || data === null) {
                    data = [];
                }
                else {
                    data = JSON.parse(data);
                    while (data.indexOf(value) !== -1) {
                        data.splice(data.indexOf(value), 1);
                    }
                }
                data.unshift(value);
                if (data.length > maxLength) {
                    data = data.slice(0, maxLength);
                }
                this.set(key, data);
            }
            catch (ex) {
                console.error(ex);
            }
        };
        LocalStorageUtils.prefix = "author.today.";
        LocalStorageUtils.RecentlyViewedKey = "recently_viewed";
        return LocalStorageUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = LocalStorageUtils;
});

},{}],60:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./ajaxUtils", "./metrikaUtils", "lodash"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ajaxUtils_1 = require("./ajaxUtils");
    var metrikaUtils_1 = require("./metrikaUtils");
    var _ = require("lodash");
    var scriptjs = require("scriptjs");
    var MerchantUtils = (function () {
        function MerchantUtils() {
        }
        MerchantUtils.getRewardTitleOptions = function () {
            return [
                "Отличная книга!",
                "Прекрасная работа",
                "Качественная и достойная вещь!",
                "Потрясающе и интригующе",
                "Мне очень нравится!",
                "Спасибо за работу, автор",
                "Потрясающе!",
                "Рекомендую!",
                "Спасибо за ваш труд!",
                "Очень увлекательно!",
                "Хорошее произведение!",
                "Восхитительная работа!",
                "Просто ОГОНЬ"
            ];
        };
        MerchantUtils.initButton = function (buyButton) {
            setTimeout(function () {
                if (buyButton.saveCard !== null) {
                    buyButton.savePaymentMethod(buyButton.saveCard);
                }
                else {
                    buyButton.savePaymentMethod(true);
                }
                var updateSaveCard = function (value) {
                    if (buyButton.processing())
                        return;
                    buyButton.processing(true);
                    ajaxUtils_1.AjaxUtils.post("account/wallet", { saveCard: value })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            buyButton.saveCard = value;
                        }
                        else {
                            buyButton.errorMessages(result.messages);
                        }
                    }).always(function () {
                        buyButton.processing(false);
                    });
                };
                buyButton.savePaymentMethod.subscribe(function (value) {
                    if (buyButton.stage() === "askToSavePaymentMethod") {
                        updateSaveCard(value);
                    }
                });
                buyButton.savePaymentMethodDontAsk.subscribe(function (value) {
                    if (buyButton.stage() === "askToSavePaymentMethod") {
                        if (value) {
                            updateSaveCard(buyButton.savePaymentMethod());
                        }
                        else {
                            updateSaveCard(null);
                        }
                    }
                });
            });
            if (buyButton.workStatus === 2) {
                buyButton.rewardTitleOptions.push("Жду продолжения!");
                buyButton.rewardTitleOptions.push("Поскорее бы проду... :-)");
                buyButton.rewardTitleOptions.push("С нетерпением жду каждую главу!");
            }
        };
        MerchantUtils.goToStage = function (stage, mode, buyButton) {
            if (stage !== "startBuyingWork" && buyButton.validation !== undefined && !buyButton.validation.isValid()) {
                buyButton.validation.errors.showAllMessages();
                return;
            }
            ;
            try {
                switch (stage) {
                    case "selectPaymentMethod":
                        switch (mode) {
                            case "work":
                            case "gift":
                                metrikaUtils_1.default.reachGoal("buyWork");
                                break;
                            case "workWithReward":
                                metrikaUtils_1.default.reachGoal("buyWorkWithReward");
                                break;
                            case "reward":
                                metrikaUtils_1.default.reachGoal("buyReward");
                                break;
                        }
                        break;
                    case "promoCode":
                        metrikaUtils_1.default.reachGoal("promoCodeForm");
                        break;
                }
            }
            catch (ex) { }
            if (buyButton.mode() !== mode) {
                buyButton.mode(mode);
            }
            buyButton.errorMessages([]);
            buyButton.stage(stage);
        };
        MerchantUtils.checkSavedBankCards = function (el, payMethod, buyButton, app) {
            if (buyButton.processing())
                return;
            buyButton.processing(true);
            var $loadingIndicator = $("<div class=\"loading-indicator\"><div class=\"la-timer la-dark\">" +
                "<div></div></div></div>");
            ajaxUtils_1.AjaxUtils.get("merchant/getSavedBankCards?payMethod=" + payMethod, null).done(function (result) {
                if (result.isSuccessful && result.data && result.data.length > 0) {
                    buyButton.errorMessages([]);
                    var options = _.map(result.data, function (x) {
                        return {
                            id: x.id,
                            cardType: x.cardType,
                            expiryMonth: x.expiryMonth,
                            expiryYear: x.expiryYear,
                            title: x.first6.substring(0, 4) + " " + x.first6.substring(4) + "XX XXXX " + x.last4
                        };
                    });
                    options.push({
                        id: null,
                        cardType: "New",
                        title: "Другая"
                    });
                    buyButton.bankcardOptions(options);
                    buyButton.selectedBankCard(options[0]);
                    buyButton.stage("fastPayment");
                }
                else {
                    var isBlocked = app.yaKassaBlocked;
                    if (isBlocked) {
                        buyButton.savePaymentMethod(false);
                    }
                    else {
                        if (buyButton.saveCard !== null) {
                            buyButton.savePaymentMethod(buyButton.saveCard);
                        }
                    }
                    setTimeout(function () {
                        if (buyButton.saveCard !== null || isBlocked) {
                            buyButton.selectPayMethod(el, payMethod);
                        }
                        else {
                            buyButton.stage("askToSavePaymentMethod");
                        }
                    }, 0);
                }
            }).always(function () {
                $loadingIndicator.remove();
                $(".pay-method > a").each(function (i, el) { $(el).parent().removeClass("temp-disabled"); });
                buyButton.processing(false);
            });
        };
        MerchantUtils.deleteSavedCard = function (buyButton) {
            if (buyButton.processing())
                return;
            buyButton.processing(true);
            var card = buyButton.selectedBankCard();
            ajaxUtils_1.AjaxUtils.post("merchant/deleteSavedCard", { id: card.id })
                .done(function (result) {
                if (result.isSuccessful) {
                    buyButton.bankcardOptions.remove(card);
                }
                else {
                    buyButton.errorMessages(result.messages);
                }
            }).always(function () {
                buyButton.processing(false);
            });
        };
        MerchantUtils.payMethodEnabled = function (buyButton, payMethods) {
            console.log('payMethods');
            console.log(payMethods);
            if (buyButton.disabledPayMethods && Array.isArray(buyButton.disabledPayMethods)) {
                for (var i = 0; i < payMethods.length; i++) {
                    if (buyButton.disabledPayMethods.indexOf(payMethods[i]) === -1) {
                        console.log('payMethodEnabled=true1');
                        return true;
                    }
                }
                console.log('payMethodEnabled=false');
                return false;
            }
            console.log('payMethodEnabled=true2');
            return true;
        };
        MerchantUtils.createOder = function (el, payMethod, buyButton, successCallback) {
            var _this = this;
            if (buyButton.processing())
                return;
            if (!buyButton.payMethodEnabled(payMethod))
                return;
            buyButton.processing(true);
            $(".pay-method > a").each(function (i, el) { $(el).parent().addClass("temp-disabled"); });
            if ($(el).is("a")) {
                var $loadingIndicator = $("<div class=\"loading-indicator\"><div class=\"la-timer la-dark\">" +
                    "<div></div></div></div>");
                $loadingIndicator.appendTo(el);
            }
            var mode = buyButton.mode();
            var savePaymentMethod = buyButton.savePaymentMethod();
            if (payMethod !== "CreditCard" && payMethod !== "YaKassa" && payMethod !== "SberPay" && payMethod !== "Tinkoff" && payMethod !== "TinkoffCard") {
                savePaymentMethod = false;
            }
            var orderData = {
                workId: buyButton.workId,
                seriesId: buyButton.seriesId,
                payMethod: payMethod,
                savePaymentMethod: savePaymentMethod,
                mode: mode,
                price: buyButton.price
            };
            if (mode === "workWithReward" || mode === "reward" || mode === "wallet") {
                orderData.rewardPrice = buyButton.rewardValue();
                orderData.rewardTitle = buyButton.rewardTitle();
            }
            var selectedCard = buyButton.selectedBankCard();
            if (selectedCard && selectedCard.cardType !== "New") {
                orderData.savedCardId = selectedCard.id;
            }
            ajaxUtils_1.AjaxUtils.post("merchant/createWorkOrder", orderData).done(function (result) {
                if (result.isSuccessful) {
                    try {
                        metrikaUtils_1.default.reachGoal("createOrder", {
                            order_price: buyButton.price,
                            currency: "RUB",
                            orderId: result.data.orderId,
                            workId: buyButton.workId,
                            seriesId: buyButton.seriesId,
                            workStatus: buyButton.workStatus,
                            workTitle: buyButton.workTitle,
                            payMethod: payMethod,
                            savePaymentMethod: savePaymentMethod
                        });
                        if (successCallback)
                            successCallback(buyButton, result);
                    }
                    catch (ex) {
                        console.log(ex);
                    }
                    setTimeout(function () {
                        var method = result.data.method || "post";
                        if (method === "get") {
                            window.location.href = result.data.url;
                            return;
                        }
                        if (method === "widget") {
                            if (payMethod === "PaySelection") {
                                _this.processPaySelectionOrder(result.data, buyButton);
                                return;
                            }
                            else if (payMethod === "CloudPayments") {
                                _this.processCloudPaymentsOrder(result.data, buyButton);
                                return;
                            }
                        }
                        if (method === "post") {
                            var $form = $("<form action=\"" + result.data.url + "\" method=\"post\" accept-charset=\"UTF-8\" style=\"display: none\">");
                            if (result.data.formData) {
                                _.each(JSON.parse(result.data.formData), function (v, k) {
                                    if (_.isString(v)) {
                                        var $input = $("<input/>", {
                                            name: k,
                                            value: v
                                        });
                                        $form.append($input);
                                    }
                                    else {
                                        _.each(v, function (arr) {
                                            var $input = $("<input/>", {
                                                name: k,
                                                value: arr
                                            });
                                            $form.append($input);
                                        });
                                    }
                                });
                            }
                            $("body").append($form);
                            $form.submit();
                        }
                    }, 1000);
                }
                else {
                    buyButton.errorMessages(result.messages);
                }
            })
                .always(function () {
                setTimeout(function () {
                    if ($(el).is("a")) {
                        $loadingIndicator.remove();
                    }
                    $(".pay-method > a").each(function (i, el) { $(el).parent().removeClass("temp-disabled"); });
                    buyButton.processing(false);
                    if ($(el).is("button")) {
                        $(el).removeClass("is-loading");
                        $(el).removeAttr("disabled");
                    }
                }, 1000);
            });
        };
        MerchantUtils.processCloudPaymentsOrder = function (data, buyButton) {
            scriptjs(["https://widget.cloudpayments.ru/bundles/cloudpayments.js"], function () {
                var widget = new cp.CloudPayments();
                widget.pay('charge', {
                    publicId: data.publicId,
                    description: "\u041E\u043F\u043B\u0430\u0442\u0430 \u0437\u0430\u043A\u0430\u0437\u0430 #" + data.orderId + " \u043D\u0430 Author.Today",
                    amount: data.amount,
                    currency: "RUB",
                    accountId: data.userId.toString(),
                    invoiceId: data.orderId.toString(),
                    email: data.email,
                    skin: 'mini',
                    retryPayment: false,
                    autoClose: 3,
                    configuration: {
                        common: {
                            successRedirectUrl: data.successUrl,
                            failRedirectUrl: data.failUrl
                        }
                    }
                }, {
                    onSuccess: function (options) {
                        console.log("CloudPayments: onSuccess");
                        try {
                            buyButton.modal.hide();
                        }
                        catch (e) { }
                        window.location.href = data.successUrl;
                    },
                    onFail: function (reason, options) {
                        console.error("CloudPayments: onFail: ", reason);
                        if (!(reason) || reason === "User has cancelled") {
                            // Пользователь отменил покупку или закрыл окно
                            return;
                        }
                        buyButton.errorMessages([
                            "Произошла ошибка. Пожалуйста, немного подождите и попробуйте еще раз. " +
                                "Если ошибка повторяется - сообщите об этом в службу поддержки.",
                            ("\u041F\u0440\u0438\u0447\u0438\u043D\u0430: " + reason)
                        ]);
                    },
                    onComplete: function (paymentResult, options) {
                    }
                });
            });
        };
        ;
        MerchantUtils.processPaySelectionOrder = function (data, buyButton) {
            scriptjs(["https://widget.payselection.com/lib/pay-widget.js"], function () {
                var widget = new pw.PayWidget();
                console.log("PayWidget: init");
                var widgetParams = [
                    {
                        serviceId: data.serviceId,
                        key: data.key
                    },
                    JSON.parse(data.requestBody),
                    {
                        // Варианты ключей которые могут приходить по колбекам:
                        // для onSuccess -> PAY_WIDGET:TRANSACTION_SUCCESS, PAY_WIDGET:CLOSE_AFTER_SUCCESS
                        // для onError -> PAY_WIDGET:TRANSACTION_FAIL, PAY_WIDGET:CREATE_NETWORK_ERROR, PAY_WIDGET:CREATE_BAD_REQUEST_ERROR, PAY_WIDGET:CLOSE_AFTER_FAIL, PAY_WIDGET:CLOSE_AFTER_CREATE_NETWORK_ERROR
                        // для onClose -> PAY_WIDGET:CLOSE_BEFORE_PAY
                        onSuccess: function (res) {
                            console.log("PayWidget: onSuccess", res);
                            window.location.href = data.returnUrl;
                        },
                        onError: function (res) {
                            console.error("PayWidget: onFail", res);
                            if (res.code === "CLOSE_AFTER_FAIL" ||
                                res.code === "CLOSE_AFTER_CREATE_NETWORK_ERROR") {
                                // Ошибка во время оплаты, но пользователь получил уведомление
                                return;
                            }
                            // Хак для скрытия виджета. Возможно, в будущем нужно будет убрать.
                            $("#paywidget-loader-overlay").remove();
                            $("iframe").parent().remove();
                            buyButton.errorMessages([
                                "Произошла ошибка. Пожалуйста, немного подождите и попробуйте еще раз. " +
                                    "Если ошибка повторяется - сообщите об этом в службу поддержки.",
                                ("\u041A\u043E\u0434: " + res.code)
                            ]);
                        },
                        onClose: function (res) {
                            console.log("PayWidget: onClose", res);
                            if (res.code === "PAY_WIDGET:CLOSE_BEFORE_PAY") {
                            }
                            else {
                                buyButton.errorMessages([
                                    "Вы закрыли форму при создании заказа. Если у вас возникла проблема с оплатой - сообщите об этом в службу поддержки.",
                                    ("\u041A\u043E\u0434: " + res.code)
                                ]);
                            }
                        },
                    }
                ];
                widget.pay.apply(widget, widgetParams);
            });
        };
        MerchantUtils.selectReward = function (value, buyButton) {
            if (value === "custom") {
                buyButton.isCustomRewardValue(true);
            }
            else {
                buyButton.rewardValue(value);
                buyButton.isCustomRewardValue(false);
            }
        };
        MerchantUtils.selectRewardTitle = function (index, buyButton) {
            var title = buyButton.rewardTitleOptions[index];
            if (buyButton.previousRandomTitles.indexOf(title) !== -1) {
                buyButton.selectRandomRewardTitle();
            }
            else {
                buyButton.rewardTitle(title);
                buyButton.previousRandomTitles = buyButton.previousRandomTitles.slice(0, 5);
            }
        };
        MerchantUtils.submitPromoCode = function (buyButton, successCallback) {
            if (buyButton.validation !== undefined && !buyButton.validation.isValid()) {
                buyButton.validation.errors.showAllMessages();
                return;
            }
            ;
            buyButton.errorMessages([]);
            buyButton.processing(true);
            ajaxUtils_1.AjaxUtils.post("merchant/promoCode", {
                code: buyButton.promoCode(),
                workId: buyButton.workId
            })
                .done(function (result) {
                if (result.isSuccessful) {
                    if (successCallback)
                        successCallback(buyButton);
                    try {
                        metrikaUtils_1.default.reachGoal("promoCodeActivation");
                    }
                    catch (ex) { }
                    try {
                        buyButton.reloadPage();
                    }
                    catch (ex) {
                        buyButton.fullReloadPage();
                    }
                }
                else {
                    buyButton.errorMessages(result.messages);
                }
            })
                .always(function () {
                buyButton.processing(false);
            });
        };
        return MerchantUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = MerchantUtils;
});

},{"./ajaxUtils":45,"./metrikaUtils":61,"lodash":216,"scriptjs":194}],61:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "lodash"], factory);
    }
})(function (require, exports) {
    "use strict";
    var _ = require("lodash");
    var MetrikaUtils = (function () {
        function MetrikaUtils() {
        }
        MetrikaUtils.init = function (mode) {
            $(document).off("yacounter35844850inited");
            $(document).on("yacounter35844850inited", function () {
                try {
                    console.log("Main yaCounter is ready...");
                    if (app.isAuthenticated) {
                        ym(app.yaCounterId, "setUserID", app.userId);
                    }
                    ym(app.yaCounterId, "userParams", {
                        isAuthenticated: app.isAuthenticated,
                        userId: app.userId,
                        viewMode: mode
                    });
                }
                catch (e) {
                }
            });
            if (app.yaProfileCounterId) {
                $(document).off("yacounter" + app.yaProfileCounterId + "inited");
                $(document).on("yacounter" + app.yaProfileCounterId + "inited", function () {
                    try {
                        console.log("Profile yaCounter is ready...");
                        if (app.isAuthenticated) {
                            ym(app.yaProfileCounterId, "setUserID", app.userId);
                        }
                        ym(app.yaProfileCounterId, "userParams", {
                            isAuthenticated: app.isAuthenticated,
                            userId: app.userId,
                            viewMode: mode
                        });
                    }
                    catch (e) {
                    }
                });
            }
        };
        MetrikaUtils.proxyMethod = function (methodName, params, params2) {
            try {
                var call = function (counterId) {
                    if (params2) {
                        ym(counterId, methodName, params, params2);
                    }
                    else if (params) {
                        ym(counterId, methodName, params);
                    }
                    else {
                        ym(counterId, methodName);
                    }
                };
                call(app.yaCounterId);
                call(app.yaProfileCounterId);
            }
            catch (ex) {
                console.log(ex);
            }
        };
        MetrikaUtils.hit = function (url) {
            this.proxyMethod("hit", url);
        };
        MetrikaUtils.reachGoal = function (goalName, params) {
            this.proxyMethod("reachGoal", goalName, params);
            try {
                _tmr.push({ type: "reachGoal", id: 3310925, goal: goalName });
                fbq("trackCustom", goalName, params);
            }
            catch (ex) { }
        };
        /**
         * Передача данных Ecommerce
         */
        MetrikaUtils.dataLayer_Purchase = function (orderId, products) {
            try {
                var dataLayer = window["dataLayer"] || [];
                dataLayer.push({
                    "ecommerce": {
                        "purchase": {
                            "actionField": {
                                "id": orderId
                            },
                            "products": products
                        }
                    }
                });
            }
            catch (ex) {
                console.log(ex);
            }
        };
        return MetrikaUtils;
    }());
    _.extend(window["AppUtils"], {
        Metrika: MetrikaUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = MetrikaUtils;
});

},{"lodash":216}],62:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var NavBarUtils = (function () {
        function NavBarUtils() {
        }
        NavBarUtils.init = function () {
            $("[data-search-open]").off('click').click(function () {
                var target = $(this).attr("data-search-open") || ".navbar-form";
                var $form = $(target);
                $form.addClass("open");
                $form.find("input[name='q']").focus();
                return false;
            });
            $("[data-search-dismiss]").off('click').click(function () {
                var target = $(this).attr("data-search-dismiss") || ".navbar-form";
                var $form = $(target);
                $form.removeClass("open");
                $form.find("input[name='q']").val("");
                return false;
            });
            var $body = $(document.body);
            if ($body.is(".account-layout")) {
                $(function () {
                    $("#aside-toggle").off('click').on("click", function () {
                        var $trigger = $(this);
                        if ($trigger.hasClass("open")) {
                            $body.addClass("aside-collapsed");
                            $trigger.removeClass("open");
                        }
                        else {
                            $trigger.addClass("open");
                            $body.removeClass("aside-collapsed");
                        }
                        $(window).trigger("resize");
                    });
                    $(".wrapper .aside + section.content").off('click').on("click", function () {
                        if (!$body.hasClass("aside-collapsed")) {
                            $body.addClass("aside-collapsed");
                            $("#aside-toggle").removeClass("open");
                        }
                    });
                });
            }
        };
        return NavBarUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = NavBarUtils;
});

},{"jquery":214}],63:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var oAuthUtils = (function () {
        function oAuthUtils() {
        }
        oAuthUtils.generateRandomString = function () {
            var array = new Uint32Array(56 / 2);
            window.crypto.getRandomValues(array);
            var s = '';
            for (var i = 0; i < array.length; i++) {
                s += ('0' + array[i].toString(16)).substr(-2);
            }
            return s;
        };
        oAuthUtils.sha256 = function (plain, callback) {
            var data = oAuthUtils.str2ab(plain);
            window.crypto.subtle.digest('SHA-256', data).then(function (hashed) {
                callback(hashed);
            });
        };
        oAuthUtils.str2ab = function (str) {
            var buf = new ArrayBuffer(str.length);
            var bufView = new Uint8Array(buf);
            for (var i = 0, strLen = str.length; i < strLen; i++) {
                bufView[i] = str.charCodeAt(i);
            }
            return bufView;
        };
        oAuthUtils.base64urlencode = function (a) {
            var str = "";
            var bytes = new Uint8Array(a);
            var len = bytes.byteLength;
            for (var i = 0; i < len; i++) {
                str += String.fromCharCode(bytes[i]);
            }
            return btoa(str)
                .replace(/\+/g, "-")
                .replace(/\//g, "_")
                .replace(/=+$/, "");
        };
        oAuthUtils.challenge_from_verifier = function (v, callback) {
            oAuthUtils.sha256(v, function (hashed) {
                var base64encoded = oAuthUtils.base64urlencode(hashed);
                callback(base64encoded);
            });
        };
        return oAuthUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = oAuthUtils;
});

},{}],64:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash", "toastr", "../viewModels/base/baseViewModel", "../components/modalDialog", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var toastr = require("toastr");
    var baseViewModel_1 = require("../viewModels/base/baseViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var PostUtils = (function (_super) {
        __extends(PostUtils, _super);
        function PostUtils() {
            _super.call(this);
        }
        PostUtils.prototype.vote = function (btn, postId, vote) {
            var $icon = $(btn), $btn = $icon.parent();
            if ($btn.attr("disabled"))
                return;
            $btn.attr("disabled", "disabled");
            var toggleClass = "toggle", $rating = $btn.siblings(".rating-count"), voteId = $rating.attr("data-vote-id");
            if (!$icon.hasClass(toggleClass)) {
                $btn.addClass("animate");
                setTimeout(function () {
                    $btn.removeClass("animate");
                }, 500);
            }
            ajaxUtils_1.AjaxUtils.post("post/vote", {
                voteId: voteId,
                targetId: postId,
                isLiked: $icon.hasClass(toggleClass) ? null : vote === 1
            }).done(function (result) {
                if (result.isSuccessful) {
                    $rating.html(result.data.rating);
                    $rating.attr("data-vote-id", result.data.voteId);
                    if ($icon.hasClass(toggleClass)) {
                        $icon.removeClass(toggleClass);
                        $icon.addClass("hover-state-canceled");
                        $icon.on("mouseleave", function () {
                            $icon.removeClass("hover-state-canceled");
                            $icon.off("mouseleave");
                        });
                    }
                    else {
                        $btn.siblings().find(".like, .dislike").removeClass(toggleClass);
                        $icon.removeClass("hover-state-canceled");
                        $icon.addClass(toggleClass);
                    }
                }
                else if (result.isWarning) {
                    toastr.warning(result.messages[0]);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                $btn.removeAttr("disabled");
            });
        };
        PostUtils.prototype.toggleFavorite = function (btn, postId) {
            var _this = this;
            var $btn = $(btn), $icon = $btn.find("i");
            if ($btn.attr("disabled"))
                return;
            $btn.attr("disabled", "disabled");
            var toggleClass = "toggle", isActive = $icon.hasClass(toggleClass);
            if (!isActive) {
                $btn.addClass("animate");
                setTimeout(function () {
                    $btn.removeClass("animate");
                }, 500);
            }
            var ajaxSetFavor = function () {
                ajaxUtils_1.AjaxUtils.post("post/toggleFavorite", {
                    postId: postId,
                    toggle: !isActive
                }).done(function (result) {
                    if (result.isSuccessful) {
                        if (isActive) {
                            $icon.removeClass(toggleClass);
                            $btn.attr("data-hint", "Добавить пост в сохраненные");
                        }
                        else {
                            $icon.addClass(toggleClass);
                            $btn.attr("data-hint", "Удалить пост из сохраненных");
                        }
                    }
                    else if (result.isWarning) {
                        toastr.warning(result.messages[0]);
                    }
                    else {
                        alert(result.messages[0]);
                    }
                }).always(function () {
                    $btn.removeAttr("disabled");
                });
            };
            if (isActive) {
                this.showModal({
                    title: "Вы уверены?",
                    message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u043E\u0441\u0442 \u0438\u0437 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0445?",
                    maxWidth: "400px",
                    type: modalDialog_1.ModalType.ConfirmDelete,
                    deleteBtnText: "Удалить",
                    onSubmit: function () {
                        ajaxSetFavor();
                        _this.modal.hide();
                    }
                });
                $btn.removeAttr("disabled");
            }
            else {
                ajaxSetFavor();
            }
        };
        PostUtils.prototype.toggleUserPinned = function (btn, postId, toogle) {
            var _this = this;
            var $btn = $(btn);
            var postPinnedClass = 'post-pinned', toogleClass = 'toogle', isActive = $btn.hasClass(toogleClass);
            if ($btn.attr("disabled"))
                return;
            $btn.attr("disabled", "disabled");
            ajaxUtils_1.AjaxUtils.post("post/toggleUserPin", {
                objectId: postId,
                enabled: !isActive
            }).done(function (result) {
                if (result.isSuccessful) {
                    if (!isActive) {
                        $("." + postPinnedClass + "." + toogleClass).removeClass(toogleClass);
                    }
                    $btn.addClass(toogleClass);
                    toastr.success(result.messages[0]);
                    setTimeout(function () {
                        _this.reloadPage();
                    }, 1000);
                }
                else if (result.isWarning) {
                    toastr.warning(result.messages[0]);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                $btn.removeAttr("disabled");
            });
        };
        PostUtils.startViewStatsCollector = function () {
            try {
                var $posts = $(".post");
                var observerElements = $posts.toArray();
                // Создаем новый observer (наблюдатель)
                var observer_1 = new window["IntersectionObserver"](function (entries) {
                    entries.forEach(function (entry) {
                        if (entry.isIntersecting) {
                            setTimeout(function () {
                                var parent = entry.target.parentNode;
                                if (observerElements.indexOf(parent) >= 0 &&
                                    entry.target.getBoundingClientRect().bottom > 0 &&
                                    entry.target.getBoundingClientRect().top < document.documentElement.clientHeight) {
                                    observerElements = observerElements.filter(function (elem) { return elem !== parent; });
                                    var id = $(parent).attr("id").split("_")[1];
                                    ajaxUtils_1.AjaxUtils.post(app.statsApiUrl + "post/hit/" + id, {});
                                }
                            }, 10000); // 10 секунд
                        }
                    });
                });
                $posts.find(".rich-content").each(function (index, el) {
                    observer_1.observe(el);
                });
            }
            catch (e) {
                console.error(e);
            }
        };
        return PostUtils;
    }(baseViewModel_1.BaseViewModel));
    _.extend(window["AppUtils"], {
        Post: new PostUtils()
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = PostUtils;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../viewModels/base/baseViewModel":92,"jquery":214,"lodash":216,"toastr":199}],65:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "lodash", "../viewModels/base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var _ = require("lodash");
    var baseViewModel_1 = require("../viewModels/base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ProfileUtils = (function (_super) {
        __extends(ProfileUtils, _super);
        function ProfileUtils() {
            _super.call(this);
        }
        ProfileUtils.prototype.showConfirmDeleteAvatarModal = function (id) {
            var _this = this;
            this.showModal({
                title: "Удаление фотографии",
                message: "Вы уверены, что хотите удалить фотографию?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("account/moderatorDeleteProfileImage", { id: id })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            _this.fullReloadPage();
                        }
                    });
                }
            });
        };
        ProfileUtils.prototype.showConfirmDeleteBgModal = function (id) {
            var _this = this;
            this.showModal({
                title: "Удаление фонового изображения",
                message: "Вы уверены, что хотите удалить фоновое изображение?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("account/moderatorDeleteProfileBgImage", { id: id })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            _this.fullReloadPage();
                        }
                    });
                }
            });
        };
        return ProfileUtils;
    }(baseViewModel_1.BaseViewModel));
    _.extend(window["AppUtils"], {
        Profile: new ProfileUtils()
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ProfileUtils;
});

},{"../utils/ajaxUtils":45,"../viewModels/base/baseViewModel":92,"lodash":216}],66:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", '../utils/indexedDbUtils', "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var indexedDbUtils_1 = require('../utils/indexedDbUtils');
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ReadingProgressUtils = (function () {
        function ReadingProgressUtils() {
        }
        ReadingProgressUtils.check = function (userId, workId, chapterId, chapterProgress) {
            var _this = this;
            try {
                indexedDbUtils_1.IndexedDb.db.readingProgress.where({ "userId": userId, "workId": workId }).first()
                    .then(function (progress) {
                    if (progress && (progress.chapterId != chapterId || progress.chapterProgress - chapterProgress > _this.toleranceValue)) {
                        ajaxUtils_1.AjaxUtils.post("reader/reading-progress-tracking", {
                            workId: workId,
                            chapterId: progress.chapterId,
                            chapterProgress: progress.chapterProgress,
                            workProgress: progress.workProgress,
                            cachedChapterId: chapterId,
                            cachedChapterProgress: chapterProgress
                        });
                    }
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        ReadingProgressUtils.updateIfNeeded = function (userId, workId, chapterId, chapterProgress, workProgress, sessionId) {
            try {
                indexedDbUtils_1.IndexedDb.db.readingProgress.where({ "userId": userId, "workId": workId }).first()
                    .then(function (progress) {
                    if (progress) {
                        if (!(progress.sessionId == sessionId && workProgress < progress.workProgress)) {
                            indexedDbUtils_1.IndexedDb.db.readingProgress.update(progress.id, { chapterId: chapterId, chapterProgress: chapterProgress, workProgress: workProgress });
                        }
                    }
                    else {
                        indexedDbUtils_1.IndexedDb.db.readingProgress.add({ userId: userId, workId: workId, chapterId: chapterId, chapterProgress: chapterProgress, workProgress: workProgress, sessionId: sessionId });
                    }
                });
            }
            catch (e) {
                console.log(e);
            }
        };
        ReadingProgressUtils.toleranceValue = 0.5;
        return ReadingProgressUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ReadingProgressUtils;
});

},{"../utils/ajaxUtils":45,"../utils/indexedDbUtils":58}],67:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var RichContentUtils = (function () {
        function RichContentUtils() {
        }
        RichContentUtils.replaceEmoji = function (html) {
            try {
                var $div = $("<div/>").html(html);
                $div.find("img.emojione").each(function (i, el) {
                    var $el = $(el), src = $el.attr("src"), alt = $el.attr("alt");
                    var $span = $("<span/>", {
                        "class": "emojione fr-emoticon fr-deletable fr-emoticon-img",
                        "data-emoji": alt,
                        css: {
                            'background-image': "url(" + src + ")"
                        },
                        text: "&nbsp;"
                    });
                    html = html.replace(el.outerHTML, $span[0].outerHTML);
                });
            }
            catch (ex) {
                console.error(ex);
            }
            return html;
        };
        RichContentUtils.richTextToFroala = function (html) {
            try {
                html = this.replaceEmoji(html);
                var $div = $("<div/>").html(html);
                $div.find(".spoiler").each(function (i, el) {
                    var $el = $(el), title = $el.find(".spoiler-title").first().text(), content = $el.find(".spoiler-content").first().html();
                    var spoilerHtml = ("<p>[spoiler=" + title + "]</p>") + content + "<p>[/spoiler]</p>";
                    html = html.replace(el.outerHTML, spoilerHtml);
                });
            }
            catch (ex) {
                console.error(ex);
            }
            return html;
        };
        RichContentUtils.processHtml = function (html) {
            $(html).find(".rich-content").each(function (i, el) {
                $(".img-gif").each(function (ind, el) {
                    var $el = $(el);
                    if ($el.data("gif-init"))
                        return;
                    $el.data("gif-init", true);
                    var prevImage = $el.attr("data-src");
                    var srcImage = $el.attr("data-gif");
                    $el.bind("load", function () {
                        if ($el.width() < 100 || $el.width < 100) {
                            $el.attr("src", srcImage);
                            $el.unbind("load");
                            return;
                        }
                        var a = document.createElement("a");
                        a.href = srcImage;
                        var html = $('<div class="gif-preview">' +
                            '		<div class="gif-preview-wrapper">' +
                            '			<img class="gif-preview-img" src="' + prevImage + '" style="' + $el.attr("style") + '">' +
                            '			<div class="gif-preview-button">' +
                            '				<div class="gif-preview-bg"></div>' +
                            '				<div class="gif-preview-circle"></div>' +
                            '				<div class="gif-preview-label"></div>' +
                            "			</div>" +
                            "		</div>" +
                            '		<div class="gif-preview-fotter">' +
                            '			<a href="' + srcImage + '" target="_blank" class="gif-preview-icon"></a>' +
                            "		</div>" +
                            "</div>");
                        $el.css("display", "none");
                        $(html).insertAfter(el);
                        var $btn = $(html).find(".gif-preview-button");
                        var $circle = $(html).find(".gif-preview-circle");
                        var $footer = $(html).find(".gif-preview-fotter");
                        var $gifImage = $(html).find(".gif-preview-img");
                        $(html).find(".gif-preview-wrapper").click(function () {
                            if ($gifImage.data("is-gif")) {
                                $gifImage.show();
                                $circle.removeClass("gif-preview-rotating");
                                $footer.show();
                                $btn.show();
                                $gifImage.attr("src", prevImage);
                                $gifImage.data("is-gif", false);
                            }
                            else {
                                $circle.addClass("gif-preview-rotating");
                                $footer.hide();
                                $gifImage.attr("src", srcImage);
                                $gifImage.bind("load", function () {
                                    $circle.removeClass("rotating");
                                    $btn.hide();
                                    $gifImage.unbind("load");
                                });
                                $gifImage.data("is-gif", true);
                            }
                        });
                    });
                });
            });
        };
        return RichContentUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = RichContentUtils;
});

},{"jquery":214}],68:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var Sharer = (function () {
        function Sharer(elem) {
            this.elem = elem;
        }
        Sharer.prototype.getValue = function (attr) {
            var val = this.elem.getAttribute('data-' + attr);
            return (val === undefined || val === null) ? false : val;
        };
        Sharer.prototype.share = function () {
            var sharer = this.getValue('sharer').toLowerCase(), sharers = {
                facebook: {
                    shareUrl: 'https://www.facebook.com/sharer/sharer.php',
                    params: { u: this.getValue('url') }
                },
                googleplus: {
                    shareUrl: 'https://plus.google.com/share',
                    params: { url: this.getValue('url') }
                },
                linkedin: {
                    shareUrl: 'https://www.linkedin.com/shareArticle',
                    params: {
                        url: this.getValue('url'),
                        mini: true
                    }
                },
                twitter: {
                    shareUrl: 'https://twitter.com/intent/tweet/',
                    params: {
                        text: this.getValue('title'),
                        url: this.getValue('url'),
                        hashtags: this.getValue('hashtags'),
                        via: this.getValue('via')
                    }
                },
                email: {
                    shareUrl: 'mailto:' + this.getValue('to'),
                    params: {
                        subject: this.getValue('subject'),
                        body: this.getValue('title') + '\n' + this.getValue('url')
                    },
                    isLink: true
                },
                whatsapp: {
                    shareUrl: 'whatsapp://send',
                    params: {
                        text: this.getValue('title') + ' ' + this.getValue('url')
                    },
                    isLink: true
                },
                telegram: {
                    shareUrl: 'https://t.me/share/url',
                    params: {
                        url: this.getValue('url'),
                        text: this.getValue('title')
                    }
                },
                viber: {
                    shareUrl: 'viber://forward',
                    params: {
                        text: this.getValue('title') + ' ' + this.getValue('url')
                    },
                    isLink: true
                },
                line: {
                    shareUrl: 'http://line.me/R/msg/text/?' + encodeURIComponent(this.getValue('title') + ' ' + this.getValue('url')),
                    isLink: true
                },
                pinterest: {
                    shareUrl: 'https://www.pinterest.com/pin/create/button/',
                    params: {
                        url: this.getValue('url'),
                        media: this.getValue('image'),
                        description: this.getValue('description')
                    }
                },
                tumblr: {
                    shareUrl: 'http://tumblr.com/widgets/share/tool',
                    params: {
                        canonicalUrl: this.getValue('url'),
                        content: this.getValue('url'),
                        posttype: 'link',
                        title: this.getValue('title'),
                        caption: this.getValue('caption'),
                        tags: this.getValue('tags')
                    }
                },
                hackernews: {
                    shareUrl: 'https://news.ycombinator.com/submitlink',
                    params: {
                        u: this.getValue('url'),
                        t: this.getValue('title')
                    }
                },
                reddit: {
                    shareUrl: 'https://www.reddit.com/submit',
                    params: { 'url': this.getValue('url') }
                },
                vk: {
                    shareUrl: 'http://vk.com/share.php',
                    params: {
                        url: this.getValue('url'),
                        title: this.getValue('title'),
                        description: this.getValue('caption'),
                        image: this.getValue('image')
                    }
                },
                xing: {
                    shareUrl: 'https://www.xing.com/app/user',
                    params: {
                        'op': 'share',
                        'url': this.getValue('url'),
                        'title': this.getValue('title')
                    }
                },
                buffer: {
                    shareUrl: 'https://buffer.com/add',
                    params: {
                        url: this.getValue('url'),
                        title: this.getValue('title'),
                        via: this.getValue('via'),
                        picture: this.getValue('picture')
                    }
                },
                instapaper: {
                    shareUrl: 'http://www.instapaper.com/edit',
                    params: {
                        url: this.getValue('url'),
                        title: this.getValue('title'),
                        description: this.getValue('description')
                    }
                },
                pocket: {
                    shareUrl: 'https://getpocket.com/save',
                    params: {
                        url: this.getValue('url')
                    }
                },
                digg: {
                    shareUrl: 'http://www.digg.com/submit',
                    params: {
                        url: this.getValue('url')
                    }
                },
                stumbleupon: {
                    shareUrl: 'http://www.stumbleupon.com/submit',
                    params: {
                        url: this.getValue('url'),
                        title: this.getValue('title')
                    }
                },
                flipboard: {
                    shareUrl: 'https://share.flipboard.com/bookmarklet/popout',
                    params: {
                        v: 2,
                        title: this.getValue('title'),
                        url: this.getValue('url'),
                        t: Date.now()
                    }
                },
                weibo: {
                    shareUrl: 'http://service.weibo.com/share/share.php',
                    params: {
                        url: this.getValue('url'),
                        title: this.getValue('title'),
                        pic: this.getValue('image'),
                        appkey: this.getValue('appkey'),
                        ralateUid: this.getValue('ralateuid'),
                        language: 'zh_cn'
                    }
                },
                renren: {
                    shareUrl: 'http://share.renren.com/share/buttonshare',
                    params: {
                        link: this.getValue('url')
                    }
                },
                myspace: {
                    shareUrl: 'https://myspace.com/post',
                    params: {
                        u: this.getValue('url'),
                        t: this.getValue('title'),
                        c: this.getValue('description')
                    }
                },
                blogger: {
                    shareUrl: 'https://www.blogger.com/blog-this.g',
                    params: {
                        u: this.getValue('url'),
                        n: this.getValue('title'),
                        t: this.getValue('description')
                    }
                },
                baidu: {
                    shareUrl: 'http://cang.baidu.com/do/add',
                    params: {
                        it: this.getValue('title'),
                        iu: this.getValue('url')
                    }
                }
            }, s = sharers[sharer];
            // custom popups sizes
            if (s) {
                s.width = this.getValue('width');
                s.height = this.getValue('height');
            }
            return s !== undefined ? this.urlSharer(s) : false;
        };
        Sharer.prototype.urlSharer = function (sharer) {
            var p = sharer.params || {};
            var keys = Object.keys(p);
            var i;
            var str = keys.length > 0 ? '?' : '';
            for (i = 0; i < keys.length; i++) {
                if (str !== '?') {
                    str += '&';
                }
                if (p[keys[i]]) {
                    str += keys[i] + '=' + encodeURIComponent(p[keys[i]]);
                }
            }
            sharer.shareUrl += str;
            if (!sharer.isLink) {
                var popWidth = sharer.width || 600;
                var popHeight = sharer.height || 480;
                var left = window.innerWidth / 2 - popWidth / 2 + window.screenX;
                var top_1 = window.innerHeight / 2 - popHeight / 2 + window.screenY;
                var popParams = 'scrollbars=no, width=' + popWidth + ', height=' + popHeight + ', top=' + top_1 + ', left=' + left;
                var newWindow = window.open(sharer.shareUrl, '', popParams);
                if (window.focus) {
                    newWindow.focus();
                }
            }
            else {
                window.location.href = sharer.shareUrl;
            }
        };
        Sharer.init = function () {
            var elems = document.querySelectorAll('.sharer');
            var i;
            var l = elems.length;
            function addShare(elem) {
                var target = elem.currentTarget || elem.srcElement;
                var sharer = new Sharer(target);
                sharer.share();
            }
            for (i = 0; i < l; i++) {
                elems[i].addEventListener("click", addShare);
            }
        };
        return Sharer;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = Sharer;
});

},{}],69:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "numeral"], factory);
    }
})(function (require, exports) {
    "use strict";
    var Numeral = require("numeral");
    var language = {
        delimiters: {
            thousands: " ",
            decimal: ","
        },
        abbreviations: {
            thousand: "тыс.",
            million: "млн",
            billion: "b",
            trillion: "t"
        },
        ordinal: function () {
            // not ideal, but since in Russian it can taken on 
            // different forms (masculine, feminine, neuter)
            // this is all we can do
            return ".";
        },
        currency: {
            symbol: "₽"
        }
    };
    Numeral.language("ru", language);
    Numeral.language("ru");
    var StringUtils = (function () {
        function StringUtils() {
        }
        StringUtils.pluralize = function (number, titles) {
            var cases = [2, 0, 1, 1, 1, 2];
            return titles[(number % 100 > 4 && number % 100 < 20) ? 2 : cases[(number % 10 < 5) ? number % 10 : 5]];
        };
        StringUtils.clearFromTags = function (html) {
            var div = document.createElement("div");
            div.innerHTML = html;
            var text = div.textContent || div.innerText || "";
            return text;
        };
        StringUtils.getParam = function (name) {
            var queryString = window.location.search.replace("?", "").toLowerCase();
            var params = queryString.split("&").filter(function (p) { return p.indexOf(name) !== -1; });
            if (params.length > 0) {
                return params[0].replace(name + "=", "");
            }
            return null;
        };
        StringUtils.compareWithoutLineBreaks = function (str1, str2) {
            var lineBreakSymbols = /(\r\n|\n|\r)/gm;
            if (!str1 || !str2) {
                return false;
            }
            return str1.replace(lineBreakSymbols, " ") != str2.replace(lineBreakSymbols, " ");
        };
        return StringUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = StringUtils;
});

},{"numeral":220}],70:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "lodash", "../utils/oAuthUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var _ = require("lodash");
    var oAuthUtils_1 = require("../utils/oAuthUtils");
    var VkIdUtils = (function () {
        function VkIdUtils() {
        }
        /** Осуществляет авторизацию через VK ID */
        VkIdUtils.authorize = function (clientId, redirectUri, returnUrl) {
            if (returnUrl === void 0) { returnUrl = null; }
            if (returnUrl)
                VkIdUtils.setCookie('VkId.ReturnUrl', returnUrl);
            else
                VkIdUtils.setCookie('VkId.ReturnUrl', '');
            var verifier = oAuthUtils_1.default.generateRandomString();
            var state = oAuthUtils_1.default.generateRandomString();
            VkIdUtils.setCookie('VkId.Verifier', verifier);
            VkIdUtils.setCookie('VkId.State', state);
            oAuthUtils_1.default.challenge_from_verifier(verifier, function (codeChallenge) {
                var query = '?response_type=code'
                    + '&client_id=' + clientId
                    + '&redirect_uri=' + redirectUri
                    + '&state=' + state
                    + '&code_challenge=' + codeChallenge
                    + '&code_challenge_method=S256'
                    + '&scope=email';
                location.assign('https://id.vk.com/authorize' + query);
            });
        };
        /** Установка cookie на 60 секунд */
        VkIdUtils.setCookie = function (name, value) {
            if (value)
                document.cookie = name + '=' + encodeURIComponent(value) + '; path=/; max-age=60;';
            else
                document.cookie = name + '=0; path=/; max-age=0;';
        };
        return VkIdUtils;
    }());
    _.extend(window["AppUtils"], {
        VkId: VkIdUtils
    });
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = VkIdUtils;
});

},{"../utils/oAuthUtils":63,"lodash":216}],71:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "lodash", "crosstab", "./ajaxUtils", "../utils/localStorageUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var _ = require("lodash");
    var crosstab = require("crosstab");
    var FingerprintJS = require("fingerprint");
    var ajaxUtils_1 = require("./ajaxUtils");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var WebSocketUtils = (function () {
        function WebSocketUtils() {
        }
        WebSocketUtils.isPushDisabled = function () {
            var value = localStorageUtils_1.default.get(this.pushDisabledKey);
            if (value === undefined || value === null) {
                return false;
            }
            return value;
        };
        WebSocketUtils.isConnected = function () {
            return localStorageUtils_1.default.get(this.pushTokenIdKey);
        };
        WebSocketUtils.getPushTokenId = function () {
            return localStorageUtils_1.default.get(this.pushTokenIdKey);
        };
        WebSocketUtils.setPushTokenId = function (id) {
            localStorageUtils_1.default.set(this.pushTokenIdKey, id);
        };
        WebSocketUtils.getPushToken = function () {
            return localStorageUtils_1.default.get(this.pushTokenKey + "." + app.userId);
        };
        WebSocketUtils.savePushToken = function (token) {
            localStorageUtils_1.default.set(this.pushTokenKey + "." + app.userId, token);
            localStorageUtils_1.default.set(this.pushTokenUserIdKey, app.userId);
        };
        WebSocketUtils.disablePushNotifications = function () {
            localStorageUtils_1.default.set(this.pushDisabledKey, true);
        };
        WebSocketUtils.sendTokenToServer = function (refreshedToken, onSuccessCallback) {
            var _this = this;
            var savedToken = this.getPushToken();
            var lastUserId = localStorageUtils_1.default.get(this.pushTokenUserIdKey);
            var isSynced = savedToken === refreshedToken && lastUserId === app.userId;
            if (isSynced) {
                console.log("Token already sent to server so won\'t send it again unless it changes");
                return;
            }
            var tokenId = this.getPushTokenId();
            ajaxUtils_1.AjaxUtils.post("account/updateFirebaseToken", {
                id: tokenId,
                token: refreshedToken
            }).done(function (result) {
                if (result.isSuccessful) {
                    localStorageUtils_1.default.set(_this.pushTokenIdKey, result.data.id);
                    _this.savePushToken(refreshedToken);
                    if (onSuccessCallback) {
                        onSuccessCallback();
                    }
                }
                else {
                    console.error("UpdateFirebaseToken error: ", result.messages[0]);
                }
            });
        };
        WebSocketUtils.registerServiceWorker = function () {
            var _this = this;
            // Удаляем OneSignal
            try {
                if (navigator && navigator.serviceWorker) {
                    var oneSignalUninstalledKey_1 = "oneSignalUninstalled";
                    var oneSignalUninstalled = localStorageUtils_1.default.get(oneSignalUninstalledKey_1);
                    if (oneSignalUninstalled) {
                        console.log("OneSignalSDKWorker was already uninstalled.");
                    }
                    else {
                        navigator.serviceWorker.getRegistrations().then(function (registrations) {
                            if (!registrations.length) {
                                console.log("No serviceWorker registrations found.");
                                localStorageUtils_1.default.set("OneSignalUninstalled", true);
                                return;
                            }
                            for (var _i = 0, registrations_1 = registrations; _i < registrations_1.length; _i++) {
                                var registration = registrations_1[_i];
                                var scriptURL = registration.installing
                                    ? registration.installing.scriptURL
                                    : registration.waiting
                                        ? registration.waiting.scriptURL
                                        : registration.active
                                            ? registration.active.scriptURL
                                            : "";
                                console.log("ScriptURL: ", scriptURL);
                                if (scriptURL && scriptURL.indexOf("OneSignalSDKWorker") !== -1) {
                                    console.log("OneSignalSDKWorker was found.");
                                    registration.unregister().then(function (isOk) {
                                        if (isOk) {
                                            console.log("Successfully unregistered OneSignalSDKWorker");
                                        }
                                        else {
                                            console.log("Failed to unregister OneSignalSDKWorker");
                                        }
                                    });
                                }
                            }
                            localStorageUtils_1.default.set(oneSignalUninstalledKey_1, true);
                        });
                    }
                }
            }
            catch (ex) {
                try {
                    console.error(ex);
                }
                catch (ex2) { }
            }
            try {
                var app = window["at_firebaseApp"];
                if (app) {
                    return;
                }
                var firebaseConfig = {
                    apiKey: "AIzaSyA0Sykval4lnNmJLFM5eY0_dCfvVJZmgvE",
                    //authDomain: "authortoday-b4da3.firebaseapp.com",
                    //databaseURL: "https://authortoday-b4da3.firebaseio.com",
                    projectId: "authortoday-b4da3",
                    //storageBucket: "authortoday-b4da3.appspot.com",
                    messagingSenderId: "650481789785",
                    appId: "1:650481789785:web:5ccbb36a4d7b0346"
                };
                // Initialize Firebase
                window["at_firebaseApp"] = firebase.initializeApp(firebaseConfig);
                // Retrieve Firebase Messaging object.
                var messaging = firebase.messaging();
                // Handle incoming messages. Called when:
                // - a message is received while the app has focus
                // - the user clicks on an app notification created by a service worker
                //   `messaging.setBackgroundMessageHandler` handler.
                messaging.onMessage(function (payload) {
                    console.log("Push received. ", payload);
                    var iconUrl = payload.data.largeIconUrl || window["app"].rootUrl + "dist/favicons/android-chrome-192x192.png";
                    var notification = new Notification(payload.data.contentTitle, {
                        body: payload.data.contentText,
                        dir: "auto",
                        tag: "PMMessage",
                        icon: iconUrl
                    });
                    if (payload.data.url) {
                        var url = window["app"].rootUrl + payload.data.url;
                        if (url.indexOf(location.origin) === -1) {
                            url = location.origin + url;
                        }
                        notification.onclick = function () {
                            window.open(url);
                            notification.close();
                        };
                    }
                });
                messaging.getToken({ vapidKey: "BHoD83g9Ie39LDASicR38lhqzF7t4hMTdJgpewwftIUUv4dvEeTeuCA-aOB-qWrAmNDwDsTXSaAjHURQ6p6efqE" })
                    .then(function (currentToken) {
                    if (currentToken) {
                        _this.sendTokenToServer(currentToken);
                    }
                    else {
                        // Show permission request.
                        console.log("No Instance Push ID token available. Request permission to generate one.");
                    }
                }).catch(function (err) {
                    console.log("An error occurred while retrieving token. ", err);
                });
            }
            catch (ex) {
                try {
                    console.error(ex);
                }
                catch (ex2) { }
            }
        };
        WebSocketUtils.initCrossTab = function () {
            var _this = this;
            try {
                // Проверяем заполненность LocalStorage
                try {
                    var localStorageSize = JSON.stringify(localStorage).length;
                    if (localStorageSize > 3 * 1024 * 1024) {
                        console.log("LocalStorage size is TOO big: ", localStorageSize);
                        localStorage.clear();
                        console.log("LocalStorage was cleared.");
                    }
                }
                catch (ex) {
                    console.log(ex);
                }
                // Если пользователь не авторизован, ничего не делаем.
                if (!window["app"].isAuthenticated)
                    return;
                FingerprintJS.load().then(function (fp) { return fp.get(); }).then(function (result) {
                    ajaxUtils_1.AjaxUtils.post(app.statsApiUrl + "account/track-last-activity", { id: result.visitorId }, true);
                });
                // if (window["app"].disableWebSockets) return;
                // Если уже была инициализация, то это PJAX запрос. Больше ничего делать не нужно.
                if (window["crosstab"])
                    return;
                window["crosstab"] = crosstab;
                if (!("Notification" in window)) {
                    this.html5NotificationSupported = false;
                    console.log("HTML5 Notifications unsupported.");
                }
                else {
                    this.html5NotificationSupported = true;
                }
                if (this.html5NotificationSupported) {
                    this.html5NotificationPermision = window["Notification"].permission;
                }
                else {
                    this.html5NotificationPermision = "denied";
                }
                if (this.html5NotificationPermision === "default") {
                    window["Notification"].requestPermission(function (permission) {
                        _this.html5NotificationPermision = permission;
                    });
                }
                if (!crosstab.supported) {
                    console.error("Crosstab IS NOT SUPPORTED.");
                    return;
                }
                crosstab.off("activePage");
                crosstab.on("activePage", function (message) {
                    console.log("Crosstab | activePage:", message.data);
                    window["app"].activePage = message.data;
                });
                crosstab.off("focusPage");
                crosstab.on("focusPage", function (message) {
                    window.focus();
                    if (message.data && message.data.url) {
                        window.location.href = message.data.url;
                    }
                });
                crosstab.off("unfocusPage");
                crosstab.on("unfocusPage", function (message) {
                    app.activePage = null;
                });
                crosstab.on("", function (message) {
                });
                crosstab.broadcast("activePage", window.location.href);
                $(window).on("focus", function () {
                    crosstab.broadcast("activePage", window.location.href);
                });
                $(window).on("blur beforeunload", function () {
                    crosstab.broadcast("unfocusPage", window.location.href);
                    app.activePage = null;
                });
            }
            catch (e) {
                console.error(e);
            }
        };
        WebSocketUtils.getPMTabId = function () {
            var tabs = crosstab.util.tabs;
            var pmTabId = null;
            _.forOwn(tabs, function (v, k) {
                if (v.url && v.url.indexOf("/pm") !== -1) {
                    pmTabId = v.id;
                }
            });
            return pmTabId;
        };
        WebSocketUtils.html5NotificationSupported = false;
        WebSocketUtils.pushDisabledKey = "pushDisabled";
        WebSocketUtils.pushTokenIdKey = "pushToken.id";
        WebSocketUtils.pushTokenKey = "pushToken";
        WebSocketUtils.pushTokenUserIdKey = "pushToken.userId";
        return WebSocketUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = WebSocketUtils;
});

},{"../utils/localStorageUtils":59,"./ajaxUtils":45,"crosstab":176,"fingerprint":177,"jquery":214,"lodash":216}],72:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports"], factory);
    }
})(function (require, exports) {
    "use strict";
    var WindowUtils = (function () {
        function WindowUtils() {
        }
        WindowUtils.setDirty = function (value, withPjax) {
            if (value === void 0) { value = true; }
            if (withPjax === void 0) { withPjax = true; }
            if (window.onbeforeunload && value) {
                return;
            }
            window.onbeforeunload = value
                ? function () { return true; }
                : null;
            if (withPjax) {
                var self = this;
                $(document).off('pjax:beforeSend', self.confirmFunc);
                if (value) {
                    $(document).on('pjax:beforeSend', null, { msg: self.beforeUnloadMessage, confirmCallback: self.setDirty }, self.confirmFunc);
                }
            }
        };
        WindowUtils.beforeUnloadMessage = "Внесенные изменения не сохранятся. Продолжить?";
        WindowUtils.confirmFunc = function (event) {
            if (window.onbeforeunload) {
                var choice = confirm(event.data.msg);
                if (choice) {
                    event.data.confirmCallback(false, true);
                }
                return choice;
            }
        };
        return WindowUtils;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = WindowUtils;
});

},{}],73:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "moment"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var moment = require("moment");
    var AccountEmailChangeStage;
    (function (AccountEmailChangeStage) {
        AccountEmailChangeStage[AccountEmailChangeStage["TwoFactorCode"] = 0] = "TwoFactorCode";
        AccountEmailChangeStage[AccountEmailChangeStage["SendEmail"] = 1] = "SendEmail";
    })(AccountEmailChangeStage || (AccountEmailChangeStage = {}));
    var AccountEmailChangeViewModel = (function (_super) {
        __extends(AccountEmailChangeViewModel, _super);
        function AccountEmailChangeViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.countdownSeconds = 60 * 1;
            this.isSendEmail = false;
            this.stageEnum = AccountEmailChangeStage;
            this.stage = ko.observable();
            this.twoFactorCode = ko.observable();
            this.email = ko.observable();
            this.isRetrySendCodeAvailable = ko.observable(true);
            this.email(options.email);
            var stage = options.twoFactorEnabled && (!options.nextTwoFactorRequestTime || new Date(options.nextTwoFactorRequestTime) <= moment().toDate())
                ? AccountEmailChangeStage.TwoFactorCode
                : AccountEmailChangeStage.SendEmail;
            this.stage(stage);
            this.nextAllowedSendTime = new Date(options.nextAllowedSendTime);
            this.initCoundown();
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        AccountEmailChangeViewModel.prototype.initCoundown = function () {
            var _this = this;
            if (this.nextAllowedSendTime == null) {
                this.nextAllowedSendTime = moment().add('seconds', this.countdownSeconds).toDate();
            }
            if (moment().toDate() < this.nextAllowedSendTime) {
                this.isRetrySendCodeAvailable(false);
                setTimeout(function () {
                    var countdown = $(".countdown");
                    var self = _this;
                    countdown["countdown"](_this.nextAllowedSendTime, function (event) {
                        if (event.handleObj.type === "stop" || event.offset.totalSeconds == 0) {
                            self.isRetrySendCodeAvailable(true);
                        }
                        else {
                            $(this).html(event.strftime("%M:%S"));
                        }
                    });
                });
            }
            else {
                this.isRetrySendCodeAvailable(true);
            }
        };
        AccountEmailChangeViewModel.prototype.redirectToSecurity = function () {
            location.href = app.rootUrl + "account/security";
        };
        AccountEmailChangeViewModel.prototype.back = function () {
            this.redirectToSecurity();
        };
        AccountEmailChangeViewModel.prototype.checkTwoFactorCode = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.get("account/check-tfa-code", {
                twoFactorCode: this.twoFactorCode()
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    if (_this.isSendEmail) {
                        _this.isSendEmail = false;
                        _this.sendEmail();
                    }
                    _this.stage(AccountEmailChangeStage.SendEmail);
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        AccountEmailChangeViewModel.prototype.sendEmail = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            this.initCoundown();
            setTimeout(function () {
                return ajaxUtils_1.AjaxUtils.post("account/send-email-confirmation", {
                    email: _this.email()
                }).done(function (result) {
                    _this.processing(false);
                    if (result.isSuccessful) {
                        toastr.success(result.messages[0]);
                        _this.redirectToSecurity();
                    }
                    else {
                        if (result.data && result.data.code == "TwoFactorRequired") {
                            _this.isSendEmail = true;
                            _this.stage(AccountEmailChangeStage.TwoFactorCode);
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    }
                }).always(function () {
                    _this.processing(false);
                });
            });
        };
        return AccountEmailChangeViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AccountEmailChangeViewModel;
});



},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"moment":219,"toastr":199}],74:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.countdownSeconds = 30;
            this.twoFactorEnabled = ko.observable(false);
            this.confirmEmailEnabled = ko.observable(false);
            this.login = ko.observable().extend({ required: true });
            this.password = ko.observable().extend({ required: true });
            this.code = ko.observable();
            this.sendEmailIfNeeded = ko.observable(true);
            this.isRetrySendCodeAvailable = ko.observable(true);
            this.hiddenEmail = ko.observable();
            this.loginStage = ko.computed(function () {
                return !_this.twoFactorEnabled() && !_this.confirmEmailEnabled();
            });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.startSendEmailCountdown = function () {
            this.initCountdown(moment().add('seconds', this.countdownSeconds).toDate(), this.isRetrySendCodeAvailable);
        };
        ViewModel.prototype.initCountdown = function (time, countdownEvent) {
            if (moment().toDate() < time) {
                countdownEvent(false);
                setTimeout(function () {
                    var countdown = $(".countdown");
                    countdown["countdown"](time, function (event) {
                        if (event.handleObj.type === "stop" || event.offset.totalSeconds == 0) {
                            countdownEvent(true);
                        }
                        else {
                            $(this).html(event.strftime(event.offset.totalHours == 0
                                ? "%M:%S"
                                : "%H:%M:%S"));
                        }
                    });
                });
            }
            else {
                countdownEvent(true);
            }
        };
        ViewModel.prototype.submit = function (formElement, extendedData) {
            if (extendedData != null) {
                if (extendedData.sendEmailIfNeeded != null) {
                    formElement.elements['SendEmailIfNeeded'].value = extendedData.sendEmailIfNeeded;
                    this.sendEmailIfNeeded(extendedData.sendEmailIfNeeded);
                }
            }
            else if (this.twoFactorEnabled() && !this.code()) {
                this.errorMessages(["Введите код подтверждения двухфакторной аутентификации"]);
                return;
            }
            else if (this.confirmEmailEnabled() && !this.code()) {
                this.errorMessages(["Введите код подтверждения"]);
                return;
            }
            _super.prototype.submit.call(this, formElement, extendedData);
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data.twoFactorEnabled) {
                this.twoFactorEnabled(true);
            }
            else if (result.data.confirmEmailEnabled) {
                this.confirmEmailEnabled(true);
                this.hiddenEmail(result.data.hiddenEmail);
                this.sendEmailIfNeeded(false);
                this.startSendEmailCountdown();
            }
            else {
                this.forceRedirectToPage(result.data.redirectUrl);
            }
        };
        ViewModel.prototype.resetLoginForm = function () {
            this.twoFactorEnabled(false);
            this.confirmEmailEnabled(false);
            this.login();
            this.password();
            this.code();
            this.sendEmailIfNeeded(true);
            this.isRetrySendCodeAvailable(true);
            this.hiddenEmail();
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    ;
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"./base/validatedViewModel":93,"jquery":214,"knockout":191,"moment":219}],75:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "lodash", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var _ = require("lodash");
    var Intro = require("introJs");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var MainInfoViewModel = (function (_super) {
        __extends(MainInfoViewModel, _super);
        function MainInfoViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isInitialized = false;
            this.userName = ko.observable()
                .extend({ rateLimit: 300 })
                .extend({
                required: true,
                pattern: {
                    params: /^([A-Za-z0-9_]){3,25}$/,
                    message: 'Только латинские буквы (A-Z a-z), цифры (0-9) и "_", не меньше 3 и не больше 25 символов'
                },
                validation: {
                    async: true,
                    validator: function (val, params, callback) {
                        if (!_this.isInitialized) {
                            callback(true);
                        }
                        else {
                            ajaxUtils_1.AjaxUtils.get("account/checkIfUserNameUnique", {
                                userName: val
                            })
                                .done(function (result) {
                                if (!result.isSuccessful) {
                                    _this.errorMessages(result.messages);
                                }
                                else {
                                    callback(result.data);
                                }
                            });
                        }
                    },
                    message: "Адрес уже занят."
                }
            });
            this.userNamePreview = ko.pureComputed(function () {
                var userName = _this.userName() || "";
                return "http://author.today/u/" + userName;
            });
            this.status = ko.observable().extend({
                maxLength: 140
            });
            this.day = ko.observable();
            this.days = ko.observableArray(_.range(1, 32));
            this.month = ko.observable();
            this.months = [
                { id: 1, name: "Января" }, { id: 2, name: "Февраля" }, { id: 3, name: "Марта" }, { id: 4, name: "Апреля" }, { id: 5, name: "Мая" }, { id: 6, name: "Июня" },
                { id: 7, name: "Июля" }, { id: 8, name: "Августа" }, { id: 9, name: "Сентября" }, { id: 10, name: "Октября" }, { id: 11, name: "Ноября" }, { id: 12, name: "Декабря" }
            ];
            this.year = ko.observable();
            this.years = ko.observableArray(_.range(moment().year() - 5, moment().year() - 100, -1));
            this.birthDay = ko.pureComputed(function () {
                if (!_this.day() && !_this.month() && !_this.year)
                    return new Date();
                var day = _this.day(), month = (_this.month() || 0) - 1, year = _this.year();
                var value = moment([year, month, day]);
                if (value.isValid()) {
                    return value.toISOString();
                }
                return null;
            }).extend({ date: true, required: true });
            this.birthDayPrivacyOptions = [{}];
            this.privacyShowBirthdayOptions = [
                { id: 0, name: "Не показывать дату рождения" },
                { id: 1, name: "Показывать только день и месяц" },
                { id: 2, name: "Показывать дату рождения" }];
            this.privacyShowBirthDay = ko.observable();
            this.userSex = ko.observable();
            this.userSexOptions = [{ id: -1, name: "не показывать" }, { id: 1, name: "женский" }, { id: 2, name: "мужской" }];
            this.aboutMeOptions = {
                heightMin: 100,
                heightMax: 300,
                placeholderText: "Вашим подписчикам будет интересно узнать о вас...",
                pastePlain: true,
                charCounterCount: false,
                imageDefaultDisplay: "block"
            };
            this.aboutMe = ko.observable();
            setTimeout(function () {
                _this.initValidation();
                setTimeout(function () {
                    _this.isInitialized = true;
                }, 200);
            }, 200);
            this.month.subscribe(function (monthValue) {
                _this.days(_.range(1, moment().set("y", _this.year()).month(monthValue - 1).daysInMonth() + 1));
                setTimeout(function () {
                    if (!_.includes(_this.days(), _this.day())) {
                        _this.day(1);
                    }
                });
            });
            this.year.subscribe(function (yearValue) {
                _this.days(_.range(1, moment().set("y", yearValue).month(_this.month() - 1).daysInMonth() + 1));
                setTimeout(function () {
                    if (!_.includes(_this.days(), _this.day())) {
                        _this.day(1);
                    }
                });
            });
            this.year(options.year);
            this.month(options.month);
            this.day(options.day);
            this.privacyShowBirthDay(options.privacyShowBirthDay);
            this.userSex(options.sex);
            if (options.allowModifyFIO) {
                this.fio = ko.observable().extend({
                    required: true,
                    maxLength: 50,
                    minLength: 2
                });
            }
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
        }
        MainInfoViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data.needsReload === true) {
                this.fullReloadPage();
            }
        };
        return MainInfoViewModel;
    }(validatedViewModel_1.default));
    var ContactsViewModel = (function (_super) {
        __extends(ContactsViewModel, _super);
        function ContactsViewModel() {
            _super.apply(this, arguments);
            // Contacts 
            this.webSiteUrl = ko.observable().extend({
                maxLength: {
                    params: 200,
                    message: "Длина поля должна быть не больше {0} символов."
                },
                pattern: {
                    message: "Неправильный адрес сайта",
                    params: /^((https|http)\:\/\/)?([^/]*)\.(.*)$/
                }
            });
            this.publicEmail = ko.observable().extend({
                email: {
                    params: true,
                    message: "Пожалуйста, введите правильный адрес почты"
                },
                maxLength: {
                    message: "Размер адреса почты не должен быть более 100 символов.",
                    params: 100
                }
            });
            this.vkUrl = ko.observable().extend({
                pattern: {
                    message: "Неправильный адрес страницы",
                    params: /^((https|http)\:\/\/(new.vk.com|vk.com)\/)?([a-zA-Z0-9\._]{5,})$/i
                },
                maxLength: {
                    message: "Длина ссылки не может превышать 100 символов",
                    params: 100
                }
            });
            this.facebookUrl = ko.observable().extend({
                pattern: {
                    message: "Неправильный адрес страницы",
                    params: /(?:http:\/\/)?(?:www\.)?facebook\.com\/(?:(?:\w)*#!\/)?(?:pages\/)?(?:[\w\-]*\/)*([\w\-]*)/
                },
                maxLength: {
                    message: "Длина ссылки не может превышать 100 символов",
                    params: 100
                }
            });
            this.instagramUrl = ko.observable().extend({
                pattern: {
                    message: "Неправильный адрес страницы",
                    params: /(https?)?:?(www)?instagram\.com\/[a-z].{1,255}/i
                },
                maxLength: {
                    message: "Длина ссылки не может превышать 100 символов",
                    params: 100
                }
            });
            this.telegramUrl = ko.observable().extend({
                pattern: {
                    message: "Неправильный адрес страницы",
                    params: /^((https|http)\:\/\/(www.)?t.me\/)?([a-zA-Z0-9_]{5,32})$/i
                },
                maxLength: {
                    message: "Длина ссылки не может превышать 100 символов",
                    params: 100
                }
            });
        }
        return ContactsViewModel;
    }(validatedViewModel_1.default));
    var DonationViewModel = (function (_super) {
        __extends(DonationViewModel, _super);
        function DonationViewModel() {
            _super.apply(this, arguments);
            this.$textarea = $("#otherRequisites");
            this.otherRequisitesMaxLength = 1000;
            this.donationUrl = ko.observable().extend({
                maxLength: {
                    params: 200,
                    message: "Максимальная длина ссылки {0} символов."
                }
            });
            this.donationButtonText = ko.observable().extend({
                maxLength: {
                    params: 35,
                    message: "Максимальная длина названия кнопки {0} символов."
                },
                pattern: {
                    params: /^([A-Za-zA-Яа-я0-9 ]){3,25}$/,
                    message: "Только латинские и русские буквы, цифры (0-9) и пробел, не меньше 3 и не больше 35 символов"
                }
            });
            this.otherRequisites = ko.observable();
            this.otherRequisitesOptions = {
                heightMin: 100,
                heightMax: 300,
                charCounterMax: 1000,
                placeholderText: "Например, номер WebMoney кошельков, PayPal, Boosty и т.д.",
                pastePlain: true,
                imageDefaultDisplay: "block",
                toolbarButtons: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "insertLink", "clearFormatting", "fullscreen"
                ],
                toolbarButtonsMD: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "insertLink", "clearFormatting", "fullscreen"
                ],
                toolbarButtonsSM: [
                    "bold", "italic", "underline", "strikeThrough", "|", "quote", "insertLink", "fullscreen", "|", "undo", "redo"
                ],
                toolbarButtonsXS: [
                    "bold", "|", "quote", "insertLink", "fullscreen", "|", "undo", "redo"
                ]
            };
        }
        return DonationViewModel;
    }(validatedViewModel_1.default));
    var ViewModel = (function () {
        function ViewModel(options) {
            this.mainInfo = new MainInfoViewModel(options);
            this.contacts = new ContactsViewModel(options);
            this.donation = new DonationViewModel(options);
        }
        return ViewModel;
    }());
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"introJs":187,"jquery":214,"knockout":191,"lodash":216,"moment":219}],76:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "toastr", "../utils/ajaxUtils", "../utils/webSocketUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var webSocketUtils_1 = require("../utils/webSocketUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isInitialized = ko.observable(false);
            this.isPushNotificationsSupported = ko.observable(false);
            this.notificationPermission = ko.observable("");
            this.isPushNotificationsEnabled = ko.observable(false);
            this.marketingNewsLetters = ko.observable(false);
            this.pushButtonText = ko.pureComputed(function () {
                return _this.isPushNotificationsEnabled()
                    ? "Выключить push-уведомления"
                    : "Включить push-уведомления";
            });
            this.togglePush = function () {
                if (_this.processing()) {
                    return;
                }
                _this.processing(true);
                var isEnabled = !webSocketUtils_1.default.isPushDisabled()
                    && _this.isPushNotificationsEnabled();
                var permission = _this.notificationPermission();
                if (permission === "default") {
                    toastr.info("Пожалуйста, разрешите показывать уведомления.");
                }
                else if (permission === "denied") {
                    toastr.error("Вы отключили уведомления.");
                }
                if (permission !== "granted") {
                    _this.processing(false);
                    return;
                }
                var tokenId = webSocketUtils_1.default.getPushTokenId();
                var token = webSocketUtils_1.default.getPushToken();
                if (isEnabled) {
                    ajaxUtils_1.AjaxUtils.post("account/deleteFirebaseToken", {
                        id: tokenId,
                        token: token
                    })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            _this.isPushNotificationsEnabled(false);
                            toastr.info("Вы больше не будете получать push-уведомления.");
                        }
                        else {
                            alert(result.messages[0]);
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                }
                else {
                    var messaging = firebase.messaging();
                    messaging.getToken().then(function (currentToken) {
                        if (currentToken) {
                            ajaxUtils_1.AjaxUtils.post("account/updateFirebaseToken", {
                                id: tokenId,
                                token: currentToken
                            }).done(function (result) {
                                if (result.isSuccessful) {
                                    webSocketUtils_1.default.setPushTokenId(result.data.id);
                                    webSocketUtils_1.default.savePushToken(currentToken);
                                    _this.isPushNotificationsEnabled(true);
                                    toastr.success("Спасибо за подписку на уведомления!");
                                }
                                else {
                                    console.error(result.messages[0]);
                                }
                            }).always(function () {
                                _this.processing(false);
                            });
                        }
                        else {
                            // Show permission request.
                            console.log("No Instance ID push token available. Request permission to generate one.");
                            alert("Ошибка во время выполнения запроса токена для пуш уведомлений. Пожалуйста, свяжитесь с тех. поддержкой.");
                            _this.processing(false);
                        }
                    }).catch(function (err) {
                        console.log("An error occurred while retrieving token. ", err);
                        alert("Ошибка во время получения токена для пуш уведомлений. Пожалуйста, свяжитесь с тех. поддержкой.");
                        _this.processing(false);
                    });
                }
            };
            this.webPushFrequency = ko.observable();
            this.webPushFrequencyOptions = [
                { id: 1, title: "Всегда" },
                { id: 2, title: "Не чаще одного раза в час" },
                { id: 3, title: "Не чаще двух раз в сутки" },
                { id: 4, title: "Не чаще одного раза в сутки" }
            ];
            this.marketingNewslettersChange = function () {
                if (_this.isInitialized) {
                    _this.processing(true);
                    ajaxUtils_1.AjaxUtils.post("account/updateMarketingNewsletters", {
                        marketingNewsLetters: _this.marketingNewsLetters()
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success(result.messages[0]);
                        }
                        else {
                            _this.marketingNewsLetters(!_this.marketingNewsLetters());
                            alert(result.messages[0]);
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                }
            };
            this.marketingNewsLetters(options.marketingNewsLetters);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            this.webPushFrequency(options.webPushFrequency);
            if (!("Notification" in window)) {
                this.isPushNotificationsSupported(false);
                return;
            }
            this.notificationPermission(Notification.permission);
            this.isPushNotificationsSupported(true);
            var self = this;
            try {
                if ("permissions" in navigator) {
                    navigator.permissions.query({ name: "notifications" }).then(function (notificationPerm) {
                        notificationPerm.onchange = function () {
                            var permission = notificationPerm.state;
                            console.log("User decided to change his seettings. New permission: " + permission);
                            self.notificationPermission(permission);
                            if (permission === "default") {
                                toastr.info("Пожалуйста, разрешите показывать уведомления.");
                            }
                            else if (permission === "denied") {
                                toastr.error("Вы отключили уведомления.");
                            }
                            else if (permission === "granted") {
                                self.isPushNotificationsEnabled(false);
                                self.isInitialized(true);
                            }
                        };
                    });
                }
                if (!webSocketUtils_1.default.isPushDisabled()) {
                    var messaging = firebase.messaging();
                    messaging.getToken().then(function (currentToken) {
                        if (currentToken) {
                            webSocketUtils_1.default.sendTokenToServer(currentToken);
                            var tokenId = webSocketUtils_1.default.getPushTokenId();
                            if (tokenId) {
                                ajaxUtils_1.AjaxUtils.get("account/checkFirebaseToken", { id: tokenId }).done(function (result) {
                                    if (result.isSuccessful) {
                                        _this.isPushNotificationsEnabled(result.data.isValid);
                                    }
                                    else {
                                        alert(result.messages[0]);
                                        _this.isPushNotificationsEnabled(false);
                                    }
                                    _this.isInitialized(true);
                                });
                            }
                            else {
                                _this.isPushNotificationsEnabled(false);
                                _this.isInitialized(true);
                            }
                        }
                        else {
                            // Show permission request.
                            console.log("No Instance ID push token available. Request permission to generate one.");
                        }
                    }).catch(function (err) {
                        console.log("An error occurred while retrieving token. ", err);
                        alert("Ошибка во время получения токена для пуш уведомлений. Пожалуйста, свяжитесь с тех. поддержкой.");
                    });
                }
                else {
                    this.isPushNotificationsEnabled(false);
                    this.isInitialized(true);
                }
            }
            catch (ex) {
                console.error(ex);
            }
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/webSocketUtils":71,"./base/validatedViewModel":93,"knockout":191,"toastr":199}],77:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel", "../utils/giftCodeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var giftCodeUtils_1 = require("../utils/giftCodeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            giftCodeUtils_1.default.init();
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/giftCodeUtils":55,"./base/validatedViewModel":93}],78:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "./base/validatedViewModel", "moment"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var moment = require("moment");
    var AccountPasswordChangeStage;
    (function (AccountPasswordChangeStage) {
        AccountPasswordChangeStage[AccountPasswordChangeStage["TwoFactorCode"] = 0] = "TwoFactorCode";
        AccountPasswordChangeStage[AccountPasswordChangeStage["PasswordChange"] = 1] = "PasswordChange";
    })(AccountPasswordChangeStage || (AccountPasswordChangeStage = {}));
    var AccountPasswordChangeViewModel = (function (_super) {
        __extends(AccountPasswordChangeViewModel, _super);
        function AccountPasswordChangeViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.countdownSeconds = 60 * 1;
            this.isSubmit = false;
            this.currentPassword = ko.observable().extend({ required: true });
            this.newPassword = ko.observable().extend({ required: true });
            this.confirmPassword = ko.observable().extend({
                required: true,
                equal: {
                    params: this.newPassword,
                    message: "Пароли должны совпадать"
                }
            });
            this.stageEnum = AccountPasswordChangeStage;
            this.stage = ko.observable();
            this.twoFactorCode = ko.observable();
            this.isRetrySendCodeAvailable = ko.observable(true);
            var stage = options.twoFactorEnabled && (!options.nextTwoFactorRequestTime || new Date(options.nextTwoFactorRequestTime) <= moment().toDate())
                ? AccountPasswordChangeStage.TwoFactorCode
                : AccountPasswordChangeStage.PasswordChange;
            this.stage(stage);
            this.initCoundown();
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        AccountPasswordChangeViewModel.prototype.onSubmitSucess = function (result) {
            this.redirectToSecurity();
        };
        AccountPasswordChangeViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            this.errorMessages([]);
            this.isSubmit = true;
            return callback();
        };
        AccountPasswordChangeViewModel.prototype.initCoundown = function () {
            var _this = this;
            if (this.nextAllowedSendTime == null) {
                this.nextAllowedSendTime = moment().add('seconds', this.countdownSeconds).toDate();
            }
            if (moment().toDate() < this.nextAllowedSendTime) {
                this.isRetrySendCodeAvailable(false);
                setTimeout(function () {
                    var countdown = $(".countdown");
                    var self = _this;
                    countdown["countdown"](_this.nextAllowedSendTime, function (event) {
                        if (event.handleObj.type === "stop" || event.offset.totalSeconds == 0) {
                            self.isRetrySendCodeAvailable(true);
                        }
                        else {
                            $(this).html(event.strftime("%M:%S"));
                        }
                    });
                });
            }
            else {
                this.isRetrySendCodeAvailable(true);
            }
        };
        AccountPasswordChangeViewModel.prototype.redirectToSecurity = function () {
            location.href = app.rootUrl + "account/security";
        };
        AccountPasswordChangeViewModel.prototype.back = function () {
            this.redirectToSecurity();
        };
        AccountPasswordChangeViewModel.prototype.checkTwoFactorCode = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.get("account/check-tfa-code", {
                twoFactorCode: this.twoFactorCode()
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.stage(AccountPasswordChangeStage.PasswordChange);
                    if (_this.isSubmit) {
                        _this.isSubmit = false;
                        $("#changeEmailForm").submit();
                    }
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return AccountPasswordChangeViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AccountPasswordChangeViewModel;
});



},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"moment":219}],79:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "moment", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var moment = require("moment");
    var modalDialog_1 = require("../components/modalDialog");
    var libPhoneNumber = require("libphonenumber");
    var AccountPhoneChangeStage;
    (function (AccountPhoneChangeStage) {
        AccountPhoneChangeStage[AccountPhoneChangeStage["TwoFactorCode"] = 1] = "TwoFactorCode";
        AccountPhoneChangeStage[AccountPhoneChangeStage["PhoneNumber"] = 2] = "PhoneNumber";
        AccountPhoneChangeStage[AccountPhoneChangeStage["PhoneCode"] = 3] = "PhoneCode";
    })(AccountPhoneChangeStage || (AccountPhoneChangeStage = {}));
    var AccountPhoneChangeViewModel = (function (_super) {
        __extends(AccountPhoneChangeViewModel, _super);
        function AccountPhoneChangeViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.defaultNumber = "+7";
            this.libPhoneNumber = libPhoneNumber;
            this.currentCodeType = ko.observable("voice");
            this.stageEnum = AccountPhoneChangeStage;
            this.stage = ko.observable();
            this.recaptchaRequired = ko.observable(true);
            this.confirmCodeTextTitle = ko.pureComputed(function () {
                switch (_this.currentCodeType()) {
                    case "voice":
                        return "Ответьте на звонок и <b>прослушайте</b> код";
                    case "sms":
                        return "Введите код из СМС";
                    case "flashcall":
                        return "Выполняется звонок-сброс";
                    default:
                        return "Введите код";
                }
            });
            this.confirmCodeTextInfo = ko.pureComputed(function () {
                switch (_this.currentCodeType()) {
                    case "flashcall":
                        return "\u0420\u043E\u0431\u043E\u0442 \u0441\u0434\u0435\u043B\u0430\u0435\u0442 \u0437\u0432\u043E\u043D\u043E\u043A \u043D\u0430 \u043D\u043E\u043C\u0435\u0440 " + _this.phoneNumber().substring(0, 6) + " XXX. \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0447\u0435\u0442\u044B\u0440\u0435 \u0446\u0438\u0444\u0440\u044B \u0432\u0445\u043E\u0434\u044F\u0449\u0435\u0433\u043E \u043D\u043E\u043C\u0435\u0440\u0430";
                    default:
                        return "\u041A\u043E\u0434 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u043D\u0430 \u043D\u043E\u043C\u0435\u0440 " + _this.phoneNumber().substring(0, 6) + " XXX.";
                }
            });
            this.twoFactorCode = ko.observable();
            this.phoneNumber = ko.observable();
            this.phoneNumberIsValid = ko.observable(true);
            this.countryCode = ko.observable();
            this.countryTitle = ko.pureComputed(function () {
                if (!_this.displayRegionNames)
                    return null;
                var countryCode = _this.countryCode();
                if (!countryCode)
                    return null;
                return _this.displayRegionNames.of(countryCode);
            });
            this.phoneCode = ko.observable();
            this.isRetrySendCodeAvailable = ko.observable(true);
            this.isConfirmationAvailable = ko.observable(true);
            this.isRequestCodeAvailable = ko.observable(true);
            try {
                this.displayRegionNames = new Intl.DisplayNames(["ru"], { type: "region" });
            }
            catch (ex) {
                console.log(ex);
            }
            var now = moment().toDate();
            this.recaptchaRequired(options.isRecaptchaExpire);
            var stage = AccountPhoneChangeStage.PhoneNumber;
            this.phoneNumber(options.phoneNumber || this.defaultNumber);
            if (options.twoFactorEnabled && (!options.nextTwoFactorRequestTime || new Date(options.nextTwoFactorRequestTime) <= now)) {
                stage = AccountPhoneChangeStage.TwoFactorCode;
            }
            else if (options.phoneNumber && options.phoneNumber.length > 0 && !this.recaptchaRequired()) {
                stage = AccountPhoneChangeStage.PhoneCode;
                options.lastCodeType && this.currentCodeType(options.lastCodeType);
            }
            this.stage(stage);
            this.isRequestCodeAvailable(!options.isRequestCodeBanned);
            this.nextAllowedSendTime = new Date(options.nextAllowedSendTime);
            this.initCoundown(this.nextAllowedSendTime, this.isRetrySendCodeAvailable);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            this.phoneNumber.subscribe(function (inputValue) {
                if (inputValue === null || inputValue === undefined || inputValue.replace(/\s/g, "").length < 4)
                    return;
                var phoneNumber = libPhoneNumber.parsePhoneNumber(inputValue, 'RU');
                _this.phoneNumberIsValid(phoneNumber && phoneNumber.isValid());
                if (phoneNumber) {
                    _this.countryCode(phoneNumber.country);
                    var formatedText = phoneNumber.formatInternational();
                    _this.phoneNumber(formatedText);
                }
            });
            this.isConfirmationAvailable.subscribe(function (value) {
                if (value) {
                    _this.stage(AccountPhoneChangeStage.PhoneNumber);
                }
            });
            this.isRetrySendCodeAvailable.subscribe(function (value) {
                if (value) {
                    _this.isRequestCodeAvailable(true);
                }
            });
        }
        AccountPhoneChangeViewModel.prototype.initCoundown = function (time, countdownEvent) {
            if (moment().toDate() < time) {
                countdownEvent(false);
                setTimeout(function () {
                    var countdown = $(".countdown");
                    countdown["countdown"](time, function (event) {
                        if (event.handleObj.type === "stop" || event.offset.totalSeconds == 0) {
                            countdownEvent(true);
                        }
                        else {
                            $(this).html(event.strftime(event.offset.totalHours == 0
                                ? "%M:%S"
                                : "%H:%M:%S"));
                        }
                    });
                });
            }
            else {
                countdownEvent(true);
            }
        };
        AccountPhoneChangeViewModel.prototype.redirectToSecurity = function () {
            location.href = app.rootUrl + "account/security";
        };
        AccountPhoneChangeViewModel.prototype.back = function () {
            if (this.stage() == AccountPhoneChangeStage.PhoneCode) {
                this.stage(AccountPhoneChangeStage.PhoneNumber);
                this.phoneNumber(this.defaultNumber);
                ajaxUtils_1.AjaxUtils.post("account/clear-phone-number", {});
            }
            else {
                this.redirectToSecurity();
            }
        };
        AccountPhoneChangeViewModel.prototype.onSubmitSucess = function (result) {
            this.recaptchaRequired(false);
            this.nextAllowedSendTime = new Date(result.data.nextAllowedSendTime);
            this.currentCodeType(result.data.type);
            this.stage(AccountPhoneChangeStage.PhoneCode);
            this.errorMessages([]);
            this.initCoundown(this.nextAllowedSendTime, this.isRetrySendCodeAvailable);
        };
        AccountPhoneChangeViewModel.prototype.onSubmitFail = function (result) {
            this.showErrors(result);
        };
        AccountPhoneChangeViewModel.prototype.checkTwoFactorCode = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.get("account/check-tfa-code", {
                twoFactorCode: this.twoFactorCode()
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    if (_this.phoneNumber() && _this.phoneNumber().length > 0 && _this.phoneCode() && _this.phoneCode().length > 0) {
                        _this.confirmPhoneNumber();
                        _this.stage(AccountPhoneChangeStage.PhoneCode);
                    }
                    else {
                        _this.stage(AccountPhoneChangeStage.PhoneNumber);
                    }
                }
                else {
                    _this.showErrors(result);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        AccountPhoneChangeViewModel.prototype.sendPhoneConfirmationCode = function (type) {
            var _this = this;
            if (!this.isRetrySendCodeAvailable())
                return;
            this.errorMessages([]);
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.post("account/request-phone-confirmation-code", {
                number: this.phoneNumber(),
                type: type
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.nextAllowedSendTime = new Date(result.data.nextAllowedSendTime);
                    _this.stage(AccountPhoneChangeStage.PhoneCode);
                    _this.currentCodeType(result.data.type || type);
                    _this.initCoundown(_this.nextAllowedSendTime, _this.isRetrySendCodeAvailable);
                    _this.isRequestCodeAvailable(!result.data.isRequestCodeBanned);
                }
                else {
                    _this.showErrors(result);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        AccountPhoneChangeViewModel.prototype.confirmPhoneNumber = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            setTimeout(function () {
                return ajaxUtils_1.AjaxUtils.post("account/confirm-phone-number", {
                    number: _this.phoneNumber(),
                    code: _this.phoneCode(),
                    twoFactorCode: _this.twoFactorCode()
                }).done(function (result) {
                    _this.processing(false);
                    if (result.isSuccessful) {
                        toastr.success(result.messages[0]);
                        _this.redirectToSecurity();
                    }
                    else {
                        _this.showErrors(result);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            });
        };
        AccountPhoneChangeViewModel.prototype.showErrors = function (result) {
            if (result.data) {
                switch (result.data.code) {
                    case "PhoneNumberTaken": {
                        this.showModal({
                            title: "Номер телефона уже зарегистрирован",
                            type: modalDialog_1.ModalType.Custom,
                            templateId: "phoneNumberTaken",
                            viewModel: this,
                            maxWidth: "350px",
                            onSubmit: function () { }
                        });
                        return;
                    }
                    case "TwoFactorRequired": {
                        this.stage(AccountPhoneChangeStage.TwoFactorCode);
                        break;
                    }
                    case "RecaptchaRequired": {
                        this.recaptchaRequired(true);
                        this.stage(AccountPhoneChangeStage.PhoneNumber);
                        return;
                    }
                    case "ConfirmationBanned": {
                        this.stage(AccountPhoneChangeStage.PhoneNumber);
                        break;
                    }
                }
            }
            toastr.error(result.messages[0]);
        };
        AccountPhoneChangeViewModel.prototype.clearPhoneNumber = function () {
            this.phoneNumber("");
            this.errorMessages([]);
            this.modal.hide();
        };
        AccountPhoneChangeViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            if (!this.phoneNumberIsValid()) {
                this.showModal({
                    title: "\u041E\u0448\u0438\u0431\u043A\u0430",
                    message: "\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043D\u043E\u043C\u0435\u0440 \u0442\u0435\u043B\u0435\u0444\u043E\u043D\u0430.<br>\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043D\u043E\u043C\u0435\u0440 <b>\u0432 \u043C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u043E\u043C \u0444\u043E\u0440\u043C\u0430\u0442\u0435</b>.<br><span class='text muted'>\u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: +7 916 0000007</span>",
                    type: modalDialog_1.ModalType.Alert
                });
            }
            else {
                callback();
            }
        };
        return AccountPhoneChangeViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AccountPhoneChangeViewModel;
});



},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"libphonenumber":178,"moment":219,"toastr":199}],80:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.autoAddToLibrary = ko.observable();
            this.autoAddToLibraryOptions = [
                { id: 1, title: "Активно (рекомендуется)" },
                { id: 0, title: "Не активно" }
            ];
            this.viewLibraryId = ko.observable();
            this.viewLibraryOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.guestBookId = ko.observable();
            this.guestBookOptions = [
                { id: 1, title: "Все" },
                { id: 0, title: "Никто" }
            ];
            this.privateMessageId = ko.observable();
            this.privateMessageOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.commentsFeedId = ko.observable();
            this.commentsFeedOptions = [
                { id: 1, title: "Все" },
                { id: 0, title: "Никто" }
            ];
            this.isUnavailable = ko.observable(false);
            this.unavailableMessage = ko.observable();
            this.disableSeriesAfterword = ko.observable(false);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            this.autoAddToLibrary(options.autoAddToLibrary);
            this.viewLibraryId(options.viewLibraryId);
            this.guestBookId(options.guestBookId);
            this.privateMessageId(options.privateMessageId);
            this.commentsFeedId(options.commentsFeedId);
            this.isUnavailable(options.isUnavailable);
            this.unavailableMessage(options.unavailableMessage);
            this.disableSeriesAfterword(options.disableSeriesAfterword);
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"knockout":191}],81:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.email = ko.observable().extend({
                required: true,
                email: true
            });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.submit = function () {
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return false;
            }
            ;
            return true;
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    ;
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"knockout":191}],82:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.fio = ko.observable().extend({
                required: true,
                maxLength: 50,
                minLength: 2
            });
            this.email = ko.observable().extend({
                required: true,
                email: true,
                validation: {
                    async: true,
                    validator: function (val, params, callback) {
                        ajaxUtils_1.AjaxUtils.get("account/checkIfEmailExists", {
                            email: val
                        })
                            .done(function (result) {
                            if (!result.isSuccessful) {
                                callback({ isValid: result.data, message: result.messages.toString() });
                            }
                            else {
                                callback(result.data);
                            }
                        });
                    },
                    message: "Пользователь с такой электронной почтой уже зарегистрирован."
                }
            });
            this.password = ko.observable().extend({ required: true });
            this.termsAgree = ko.observable(false);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"knockout":191}],83:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.password = ko.observable().extend({ required: true });
            this.confirmPassword = ko.observable().extend({
                required: true,
                equal: {
                    params: this.password,
                    message: "Пароли должны совпадать"
                }
            });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    ;
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"knockout":191}],84:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isShowEmail = ko.observable(false);
            this.isShowPhoneNumber = ko.observable(false);
            this.deleteExternalIsSafe = true;
            this.confirmDeleteExternal = function (formId) {
                if (_this.deleteExternalIsSafe) {
                    $(formId).submit();
                    return;
                }
                _this.showModal({
                    title: "Отключение стороннего аккаунта",
                    deleteBtnText: "Отключить",
                    message: "Вы уверены, что хотите отключить сторонний аккаунт?"
                        + "<br />Это приведет к сбросу статуса \"Подтвержденный\" для аккаунта на Author.Today."
                        + "<br /><a href=\"" + window["app"].rootUrl + "account/identification\">Подробнее о подтверждении аккаунта</a>.",
                    onSubmit: function () {
                        $(formId).submit();
                    }
                });
            };
            this.deleteExternalIsSafe = options.deleteExternalIsSafe;
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.reloadPage();
        };
        ViewModel.prototype.show2FaMessage = function () {
            var _this = this;
            setTimeout(function () {
                _this.showModal({
                    title: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F",
                    type: 3,
                    message: "При входе на author.today через сторонние аккаунты ключ двухфакторной аутентификации не запрашивается"
                });
            }, 100);
        };
        ViewModel.prototype.showOther = function () {
            $('#other-last-actyvity').show();
            $('#show-last-actyvity').hide();
        };
        ViewModel.prototype.showEmail = function () {
            this.isShowEmail(true);
        };
        ViewModel.prototype.showPhoneNumber = function () {
            this.isShowPhoneNumber(true);
        };
        ViewModel.prototype.showConfirmRefreshSecurityStampModal = function () {
            this.showModal({
                title: "Завершение сеансов",
                deleteBtnText: "Завершить",
                message: "Вы уверены, что хотите завершить сеансы?",
                onSubmit: function () {
                    $("#refreshSecurityStampForm").submit();
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    ;
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"jquery":214,"knockout":191}],85:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "../components/modalDialog", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var stringUtils_1 = require("../utils/stringUtils");
    var Clipboard = require("clipboard");
    var AccountMainInfoViewModel = (function (_super) {
        __extends(AccountMainInfoViewModel, _super);
        function AccountMainInfoViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.initialYaMetrikaEmail = this.options.yaMetrikaEmail;
            this.clipboard = null;
            this.isShowEmail = ko.observable(false);
            this.yaMetrikaFormActive = ko.observable(false);
            this.infoMessage = ko.observable();
            this.isEditing = ko.observable(false);
            this.yaMetrikaSubmitEnable = ko.pureComputed(function () {
                return _this.yaMetrikaEmail() && _this.yaMetrikaEmail() != _this.initialYaMetrikaEmail;
            });
            this.yaMetrikaEmail = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.yaMetrikaFormActive();
                    }
                },
                email: true,
                maxLength: 256
            });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            if (this.clipboard) {
                this.clipboard.destroy();
            }
            this.clipboard = new Clipboard("#copyUserIdBtn", {
                text: function (el) { return $(el).attr("data-clipboard"); }
            });
            this.clipboard.off("sucess");
            this.clipboard.on("success", function (e) {
                var $el = $(e.trigger);
                $el.attr("data-hint-prev", $el.attr("data-hint"))
                    .attr("data-hint", "Номер скопирован")
                    .addClass("hint-always");
                setTimeout(function () {
                    $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                }, 3000);
            });
            this.clipboard.on("error", function (e) {
                var $el = $(e.trigger);
                var url = location.origin + $el.attr("data-clipboard");
                prompt("Чтобы скопировать промокод, нажмите Ctrl+C и потом Enter.", url);
            });
        }
        AccountMainInfoViewModel.prototype.showEmail = function () {
            this.isShowEmail(true);
        };
        AccountMainInfoViewModel.prototype.showDeleteUserGrantConfirmationDialog = function () {
            var _this = this;
            this.processing(true);
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u0443",
                type: 2,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0442\u043E\u0437\u0432\u0430\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043B\u044F \u043F\u043E\u0447\u0442\u044B " + this.initialYaMetrikaEmail + "?",
                onHide: function () { _this.processing(false); },
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("account/metrika", {}).done(function (result) {
                        _this.processing(false);
                        if (result.isSuccessful) {
                            toastr.success(result.messages[0]);
                            _this.modal.hide();
                            _this.reloadPage();
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                    ;
                }
            });
        };
        AccountMainInfoViewModel.prototype.btnYaMetrikaClick = function () {
            this.yaMetrikaFormActive(true);
            return true;
        };
        AccountMainInfoViewModel.prototype.checkHasCoAuthorWorks = function () {
            var _this = this;
            this.infoMessage();
            this.processing(true);
            ajaxUtils_1.AjaxUtils.get("account/get-coauthor-works-count", {}).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful && result.data) {
                    if (result.data > 0) {
                        _this.infoMessage("\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C " + stringUtils_1.default.pluralize(result.data, ["произведение, написанное", (result.data + " \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F, \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0445"), (result.data + " \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0439, \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0445")]) + " \u0432 \u0441\u043E\u0430\u0432\u0442\u043E\u0440\u0441\u0442\u0432\u0435. \u0422\u0430\u043A\u0438\u0435 \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F \u043D\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043A\u0440\u044B\u0442\u044B \u0438 \u0432 \u043D\u0438\u0445 \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u0443\u043F\u043E\u043C\u0438\u043D\u0430\u043D\u0438\u0435 \u043E \u0432\u0430\u0441 \u0432 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u0438\u0437 \u0430\u0432\u0442\u043E\u0440\u043E\u0432.");
                    }
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        AccountMainInfoViewModel.prototype.showDeactiveModal = function () {
            this.errorMessages([]);
            this.checkHasCoAuthorWorks();
            this.showModal({
                title: "Отключение аккаунта",
                type: modalDialog_1.ModalType.Custom,
                templateId: "deactivateAccountModal",
                maxWidth: "500px",
                viewModel: this
            });
        };
        AccountMainInfoViewModel.prototype.deactivateAccount = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            setTimeout(function () {
                return ajaxUtils_1.AjaxUtils.post("account/deactivate", {}).done(function (result) {
                    _this.processing(false);
                    if (result.isSuccessful) {
                        toastr.success(result.messages[0]);
                        _this.modal.hide();
                        _this.reloadPage();
                    }
                    else {
                        _this.errorMessages(result.messages);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            });
        };
        AccountMainInfoViewModel.prototype.showActiveModal = function () {
            this.showModal({
                title: "Включение аккаунта",
                type: modalDialog_1.ModalType.Custom,
                templateId: "activateAccountModal",
                maxWidth: "500px",
                viewModel: this
            });
        };
        AccountMainInfoViewModel.prototype.activateAccount = function () {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            setTimeout(function () {
                return ajaxUtils_1.AjaxUtils.post("account/activate", {}).done(function (result) {
                    _this.processing(false);
                    if (result.isSuccessful) {
                        toastr.success(result.messages[0]);
                        _this.reloadPage();
                        _this.modal.hide();
                    }
                    else {
                        _this.errorMessages(result.messages);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            });
        };
        AccountMainInfoViewModel.prototype.onSubmitSucess = function (result) {
            this.reloadPage();
        };
        return AccountMainInfoViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AccountMainInfoViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/stringUtils":69,"./base/validatedViewModel":93,"clipboard":202,"jquery":214,"knockout":191,"toastr":199}],86:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var Clipboard = require("clipboard");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.clipboard = null;
            this.code = ko.observable().extend({ required: true });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            if (this.clipboard) {
                this.clipboard.destroy();
            }
            this.clipboard = new Clipboard("#secretKey", {
                text: function (el) { return $(el).val(); }
            });
            this.clipboard.off("sucess");
            this.clipboard.on("success", function (e) {
                var $el = $(e.trigger).parent();
                $el.attr("data-hint-prev", $el.attr("data-hint"))
                    .attr("data-hint", "Секретный ключ скопирован")
                    .addClass("hint-always");
                setTimeout(function () {
                    $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                }, 3000);
            });
            this.clipboard.on("error", function (e) {
                var $el = $(e.trigger);
                var url = location.origin + $el.attr("data-clipboard");
                prompt("Чтобы скопировать промокод, нажмите Ctrl+C и потом Enter.", url);
            });
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.redirectToPage(result.data.redirectUrl);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"clipboard":202,"jquery":214,"knockout":191}],87:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "numeral", "./base/validatedViewModel", "../utils/ajaxUtils", "../utils/windowUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var numeral = require("numeral");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var windowUtils_1 = require("../utils/windowUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var Masonry = require("masonry-layout");
    var imagesLoaded = require("imagesloaded");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.processing = ko.observable(false);
            this.stage = ko.observable("uploadImage");
            this.numeral = numeral;
            this.titleMaxLength = 100;
            this.isNewArtUpload = false;
            this.categoryId = ko.observable();
            this.title = ko.observable().extend({
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                var characters = title.length;
                return characters + "/" + _this.titleMaxLength;
            });
            this.text = ko.observable();
            this.tags = ko.observableArray(this.options.tags || []).extend({
                maxLength: { params: 9, message: "До 9-ти тэгов через запятую, разрешены пробелы" }
            });
            this.tagsSelect2Settings = {
                placeholder: "До 9 тэгов через запятую...",
                tags: true, ajax: {
                    url: window["app"].rootUrl + "art/searchTags",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [","],
                maximumSelectionLength: 9,
                language: {
                    maximumSelected: function () { return "Вы можете выбрать не более 9 тэгов."; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    item.count = item.count || 0;
                    var markup = "<div class='clearfix'>\
                <div class='pull-left'>" + item.text + "</div>\
                <div class='pull-right'>" + item.count + "<div>\
                </div>";
                    return markup;
                }
            };
            this.filePath = ko.observable();
            this.previewOffsetLeft = ko.observable();
            this.previewOffsetTop = ko.observable();
            this.previewWidth = ko.observable();
            this.previewHeight = ko.observable();
            this.privacyCommentsId = ko.observable();
            this.privacyCommentsOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.isOwn = ko.observable();
            this.titleInit = options.titleInit;
            setTimeout(function () {
                _this.initValidation();
                _this.isOwn.subscribe(function (value) {
                    $("#isOwnWarning").collapse(value ? "show" : "hide");
                });
            }, 100);
            ko.computed(function () {
                var title = _this.title() || "";
                if (_this.isNewArtUpload || stringUtils_1.default.compareWithoutLineBreaks(title, _this.titleInit)) {
                    windowUtils_1.default.setDirty();
                }
                else {
                    windowUtils_1.default.setDirty(false);
                }
            });
            this.privacyCommentsId(options.privacyCommentsId);
            this.isOwn(options.isOwn);
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
            if (options.id !== null) {
                this.stage("cropImage");
                setTimeout(function () {
                    _this.showCropper(options, true);
                }, 0);
            }
            $(document).ready(function () {
                var uploader = new qq.FineUploader({
                    multiple: false,
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: window["app"].rootUrl + "file/uploadArt",
                        params: {
                            workId: options.workId,
                            id: options.id
                        }
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — {sizeLimit}.",
                        typeError: "{file} имеет недопустимый формат. Разрешены следующие форматы: {extensions}.",
                        tooManyItemsError: "\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 " + options.maxWorkFileUploads + " \u0444\u0430\u0439\u043B\u043E\u0432."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", "webp"],
                        sizeLimit: options.maxArtFileUploadSize
                    },
                    callbacks: {
                        onComplete: function (id, name, response) {
                            if (!response.success) {
                                alert(response.error);
                                windowUtils_1.default.setDirty(false);
                                return;
                            }
                            $("[qq-file-id=" + id + "]").remove();
                            _this.stage("cropImage");
                            setTimeout(function () { return _this.showCropper(response.data); }, 0);
                        },
                        onSubmitted: function (id, name) {
                            _this.isNewArtUpload = true;
                            windowUtils_1.default.setDirty();
                        }
                    }
                });
            });
        }
        ViewModel.prototype.showCropper = function (imgInfo, loadCropBoxData) {
            if (loadCropBoxData === void 0) { loadCropBoxData = false; }
            var cropperSize = { width: 550, height: 300 };
            var cropperAspectRatio = cropperSize.width / cropperSize.height;
            var imageAspectRatio = imgInfo.width / imgInfo.height;
            var scale = 1, previewSize = 250;
            if (imageAspectRatio >= cropperAspectRatio) {
                scale = cropperSize.height / imgInfo.height;
            }
            else {
                scale = cropperSize.width / imgInfo.width;
            }
            var cropperWidth = this.limit(scale * imgInfo.width, previewSize, cropperSize.width);
            var cropperHeight = this.limit(scale * imgInfo.height, previewSize, cropperSize.height);
            var minCropBoxWidth = Math.max(cropperWidth, cropperHeight);
            var minCropBoxHeight = minCropBoxWidth;
            if (scale < 1) {
                minCropBoxWidth = previewSize * cropperSize.width / imgInfo.width;
                minCropBoxHeight = previewSize * cropperSize.height / imgInfo.height;
            }
            var $editAvatarImage = $(".edit-art-preview");
            $editAvatarImage.cropper("destroy");
            $editAvatarImage.attr("src", imgInfo.url);
            var cropperOptions = {
                aspectRatio: 1,
                viewMode: 1,
                movable: false,
                scalable: false,
                zoomable: false,
                doubleClickToggle: false,
                minCropBoxWidth: minCropBoxWidth,
                minCropBoxHeight: minCropBoxHeight,
                checkCrossOrigin: false
            };
            if (loadCropBoxData) {
                cropperOptions.data = {
                    x: parseInt(this.previewOffsetLeft()),
                    y: parseInt(this.previewOffsetTop()),
                    width: parseInt(this.previewWidth()),
                    height: parseInt(this.previewHeight())
                };
            }
            $editAvatarImage.cropper(cropperOptions);
            this.filePath(imgInfo.url);
        };
        ViewModel.prototype.backToUpload = function () {
            this.stage("uploadImage");
        };
        ViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            this.processing(true);
            this.errorMessages([]);
            var cropBox = $(".edit-art-preview").cropper("getData", true);
            this.previewOffsetLeft(cropBox.x);
            this.previewOffsetTop(cropBox.y);
            this.previewWidth(cropBox.width);
            this.previewHeight(cropBox.height);
            setTimeout(function () { return callback(); });
        };
        ViewModel.prototype.showDeletePostModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление поста",
                message: "Вы точно хотите удалить эту иллюстрацию?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("art/delete", {
                        id: _this.options.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data && result.data.redirectUrl) {
                this.forceRedirectToPage(result.data.redirectUrl);
            }
        };
        ViewModel.prototype.limit = function (value, min, max) {
            if (value < min)
                return min;
            if (value > max)
                return max;
            return value;
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../utils/ajaxUtils":45,"../utils/stringUtils":69,"../utils/windowUtils":72,"./base/validatedViewModel":93,"imagesloaded":212,"jquery":214,"knockout":191,"lodash":216,"masonry-layout":217,"numeral":220}],88:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "../utils/richContentUtils", "../utils/socialUtils", "./commentsView"], factory);
    }
})(function (require, exports) {
    "use strict";
    var richContentUtils_1 = require("../utils/richContentUtils");
    var socialUtils_1 = require("../utils/socialUtils");
    var commentsView_1 = require("./commentsView");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            socialUtils_1.default.init();
            richContentUtils_1.default.processHtml(".art-description");
            this.loadComments(null, null, false);
        }
        return ViewModel;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/richContentUtils":67,"../utils/socialUtils":68,"./commentsView":99}],89:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "sortable", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    //@ts-ignore
    var Sortable = require("sortable");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var AudiobookChapter = (function () {
        function AudiobookChapter(options) {
            this.title = ko.observable();
            this.isEditing = ko.observable(false);
            this.processing = ko.observable(false);
            this.id = options.id;
            this.workId = options.workId;
            this.title(options.title);
            this.originalTitle = options.title;
            this.url = options.url;
        }
        AudiobookChapter.prototype.startEditing = function () {
            this.originalTitle = this.title();
            this.isEditing(true);
        };
        AudiobookChapter.prototype.cancelEditing = function () {
            this.title(this.originalTitle);
            this.isEditing(false);
        };
        AudiobookChapter.prototype.save = function () {
            var _this = this;
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.post("audiobook/renameChapter", {
                workId: this.workId,
                chapterId: this.id,
                title: this.title()
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success("\u0427\u0430\u0441\u0442\u044C \u0431\u044B\u043B\u0430 \u043F\u0435\u0440\u0435\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0430. \u041D\u043E\u0432\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435: \u00AB" + result.data.title + "\u00BB");
                    _this.title(result.data.title);
                    _this.isEditing(false);
                }
                else {
                    toastr.error(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return AudiobookChapter;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.workId = this.options.workId;
            this.allowDelete = this.options.allowDelete;
            this.useUploadedFileName = ko.observable(false);
            this.enableSorting = ko.observable(false);
            this.chapters = ko.observableArray([]);
            var rootUrl = window["app"].rootUrl;
            this.chapters(_.map(options.chapters, function (x) { return new AudiobookChapter(x); }));
            this.initSorting();
            $(document).ready(function () {
                if (!$("fine-uploader"))
                    return;
                var enableSortingValue = false;
                var uploader = new qq.FineUploader({
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: rootUrl + "audiobook/uploadChapterChunk",
                        params: {
                            workId: options.workId,
                            useUploadedFileName: function () { return _this.useUploadedFileName(); }
                        }
                    },
                    chunking: {
                        partSize: options.chunkSize,
                        enabled: true,
                        concurrent: {
                            enabled: true
                        },
                        success: {
                            endpoint: rootUrl + "audiobook/uploadChapterChunksCompleted"
                        }
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: rootUrl + "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: rootUrl + "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "Файл «{file}» слишком большой, максимальный размер файла — {sizeLimit}.",
                        typeError: "Файл «{file}» имеет недопустимый формат. Разрешены следующие форматы: {extensions}.",
                        tooManyItemsError: "\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 " + options.maxChaptersCount + " \u0444\u0430\u0439\u043B\u043E\u0432."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл",
                        waitingForResponse: "Обработка..."
                    },
                    validation: {
                        allowedExtensions: ["mp3"],
                        sizeLimit: options.maxFileUploadSize,
                        itemLimit: options.maxChaptersCount - _this.chapters().length
                    },
                    callbacks: {
                        onComplete: function (id, name, response) {
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            $("[qq-file-id=" + id + "]").remove();
                            _this.chapters.push(new AudiobookChapter(response.data));
                        },
                        onAllComplete: function () {
                            _this.enableSorting(enableSortingValue);
                            _this.reloadPage();
                        },
                        onSubmitted: function () {
                            enableSortingValue = _this.enableSorting();
                            _this.enableSorting(false);
                            $(".checkbox-edit-sorting").attr("disabled", 'disabled');
                        }
                    }
                });
                ko.computed(function () {
                    var itemLimit = options.maxChaptersCount - _this.chapters().length;
                    if (itemLimit === 0) {
                        itemLimit = -1;
                    }
                    uploader.setItemLimit(itemLimit);
                });
            });
        }
        ViewModel.prototype.initSorting = function () {
            var _this = this;
            var list = $(".sortable")[0];
            if (list) {
                var sortable = new Sortable(list, {
                    animation: 150,
                    handle: ".sortable-handle",
                    filter: ".btn",
                    onFilter: function (evt) {
                        var item = evt.item, $ctrl = $(evt.target);
                        if ($ctrl.is(".btn-simple-danger"))
                            return;
                        $ctrl.trigger(evt);
                    },
                    onEnd: function (e) {
                        ajaxUtils_1.AjaxUtils.post("audiobook/reorderChapter", {
                            workId: _this.workId,
                            oldIndex: e.oldIndex,
                            newIndex: e.newIndex
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                toastr.success("Порядок частей был изменен.");
                            }
                            else {
                                toastr.error(result.messages[0]);
                            }
                        });
                    }
                });
            }
        };
        ViewModel.prototype.updateState = function (state) {
            var _this = this;
            var message = "Подтвердите изменение статуса";
            switch (state) {
                case "InProgress":
                    if (this.options.finished) {
                        message = "Вы точно хотите отменить статус \"завершено\" у произведения?";
                    }
                    else {
                        message = "<b>Важно!</b> Если вы не собираетесь выкладывать книгу на Author.Today целиком, не меняйте данный статус. " +
                            "В случае поступления жалобы от читателя на неверный статус ваш аккаунт может быть заблокирован.";
                    }
                    break;
                case "Finished":
                    message = "Присваивая статус \"завершено\" вы подтверждаете, что <b>весь текст</b> произведения " +
                        "<b>опубликован на сайте</b> и <b>целиком доступен</b> читателю." +
                        " В противном случае выберите статус ознакомительного фрагмента.<br/>" +
                        "В случае поступления жалобы от читателя на неверный статус ваш аккаунт может быть заблокирован.";
                    break;
                case "PromoFragment":
                    message = "Выберите этот статус, если не собираетесь выкладывать книгу на Author.Today целиком.";
                    break;
            }
            this.showModal({
                title: "\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430",
                type: 2,
                okBtnText: "Продолжить",
                maxWidth: "500px",
                message: message,
                onSubmit: function () {
                    _this.processing(true);
                    return ajaxUtils_1.AjaxUtils.post("work/updateState", {
                        id: _this.workId,
                        state: state
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.modal.hide();
                            _this.reloadPage();
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                }
            });
        };
        ViewModel.prototype.publish = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/publish", {
                id: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.showMoveToDraftModal = function () {
            var _this = this;
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
                type: 2,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0435 \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A?",
                onSubmit: function () {
                    _this.processing(true);
                    return ajaxUtils_1.AjaxUtils.post("work/moveToDraft", {
                        id: _this.workId
                    }).done(function (result) {
                        _this.processing(false);
                        if (result.isSuccessful) {
                            _this.reloadPage();
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.showDeleteChapterModal = function (id, title) {
            this.showModal({
                title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0447\u0430\u0441\u0442\u0438",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u00AB" + title + "\u00BB?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("audiobook/deleteChapter", {
                        id: id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            var $el = $("#chapter_" + id);
                            $el.hide({
                                done: function () {
                                    $el.fadeOut();
                                }
                            });
                            toastr.success("\u00AB" + title + "\u00BB \u0431\u044B\u043B\u0430 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D\u0430.");
                        }
                    });
                }
            });
        };
        ViewModel.prototype.showDeleteWorkModal = function () {
            var _this = this;
            if (!this.allowDelete) {
                this.showModal({
                    title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E",
                    type: 5,
                    maxWidth: "500px",
                    message: "Вы не можете удалить произведение, т.к. доступ к нему оплатил как минимум один человек.<br/>" +
                        "Чтобы скрыть его из общего доступа, уберите  в черновики."
                });
                return;
            }
            this.showModal({
                title: "Удаление произведения",
                message: "Вы точно хотите удалить произведение?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("work/delete", {
                        id: _this.workId
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.redirectToPage(result.data.redirectUrl);
                        }
                        else {
                            _this.modal.hide();
                            _this.showModal({
                                title: "Удаление произведения",
                                message: result.messages[0],
                                type: 5
                            });
                        }
                    });
                }
            });
        };
        ViewModel.prototype.deleteFile = function (viewModel, chapter) {
            var modal = window["AppComponents"].ModalDialog;
            modal.show({
                title: "Удаление аудиофайла",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0430\u0443\u0434\u0438\u043E\u0444\u0430\u0439\u043B \u00AB" + chapter.originalTitle + "\u00BB?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("audiobook/deleteChapter", {
                        workId: viewModel.workId,
                        chapterId: chapter.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success("\u0427\u0430\u0441\u0442\u044C \u00AB" + chapter.originalTitle + "\u00BB \u0431\u044B\u043B\u0430 \u0443\u0434\u0430\u043B\u0435\u043D\u0430");
                            $("#" + chapter.id).remove();
                            viewModel.chapters.remove(chapter);
                            if (result.data && result.data.withReloadPage) {
                                viewModel.reloadPage();
                            }
                        }
                        else {
                            toastr.error(result.messages[0]);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.requestTranslationReview = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/request-translation-review", {
                id: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.updateTranslationTransStatus = function (status) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/update-translation-status", {
                id: this.workId,
                status: status
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.approveTranslation = function () {
            this.updateTranslationTransStatus('Approved');
        };
        ViewModel.prototype.rejectTranslation = function () {
            this.updateTranslationTransStatus('Rejected');
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216,"sortable":196,"toastr":199}],90:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "numeral", "../utils/ajaxUtils", "../utils/dateTimeUtils", "../utils/socialUtils", "../utils/localStorageUtils", "../utils/metrikaUtils", "../utils/imageZoomUtils", "./commentsView", "../utils/richContentUtils", "../utils/cookieUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var socialUtils_1 = require("../utils/socialUtils");
    var scriptjs = require("scriptjs");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var metrikaUtils_1 = require("../utils/metrikaUtils");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var commentsView_1 = require("./commentsView");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var cookieUtils_1 = require("../utils/cookieUtils");
    var Masonry = require("masonry-layout");
    var imagesLoaded = require("imagesloaded");
    var Settings = (function () {
        function Settings() {
        }
        return Settings;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.metricsSpentTime = 0;
            this.s3url = "audiobook/gets3url";
            this.numeral = numeral;
            this.processing = ko.observable(false);
            this.workId = this.options.workId;
            this.isATRecommended = this.options.isATRecommended;
            this.isBiblioNight = this.options.isBiblioNight;
            this.startDate = ko.observable(moment().startOf("day").add(-6, "days"));
            this.endDate = ko.observable(moment().endOf("day"));
            this.isLoading = ko.observable(true);
            this.statsViewCount = ko.observable(0);
            this.statsCommentCount = ko.observable(0);
            this.statsLikeCount = ko.observable(0);
            this.statsFilterData = ko.computed(function () {
                var filterData = {
                    startDate: _this.startDate().toISOString(),
                    endDate: _this.endDate().toISOString(),
                    itemId: _this.workId,
                    groupBy: "work"
                };
                return filterData;
            });
            this.booktrailerVideoUrl = ko.observable();
            this.showFullStats = ko.observable();
            this.currentChapter = ko.observable();
            this.chapterProgress = ko.observable();
            this.chapterDuration = ko.observable();
            this.chapterCurrentTime = ko.observable();
            this.progressComputed = ko.pureComputed(function () {
                return _this.chapterProgress();
            }).extend({
                rateLimit: {
                    timeout: 30000,
                    method: "notifyAtFixedRate"
                }
            });
            this.chapterEndTimeMessage = ko.pureComputed(function () {
                var duration = _this.chapterDuration(), currentTime = _this.chapterCurrentTime();
                var value = duration - currentTime;
                if (Math.floor(value) <= 0)
                    return _this.getTimeCode(0);
                return "-" + _this.getTimeCode(value);
            });
            this.firstPlay = true;
            this.audioVolume = ko.observable(1);
            this.audioSpeed = ko.observable(1);
            this.audioPlaying = ko.observable(false);
            this.audioWaiting = ko.observable(true);
            this.audioSpeedOptions = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
            this.previousChapter = ko.pureComputed(function () {
                var index = _this.chapters.indexOf(_this.currentChapter());
                index--;
                if (index < 0)
                    return null;
                return _this.chapters[index];
            });
            this.nextChapter = ko.pureComputed(function () {
                var index = _this.chapters.indexOf(_this.currentChapter());
                index++;
                if (index >= _this.chapters.length)
                    return null;
                return _this.chapters[index];
            });
            this.audioPlayerIcon = ko.pureComputed(function () {
                var waiting = _this.audioWaiting(), playing = _this.audioPlaying();
                if (playing && waiting) {
                    return "icon-spinner icon-spin-animate";
                }
                if (playing) {
                    return "icon-2-player-pause";
                }
                return "icon-2-player-play";
            });
            this.registerUrl = app.rootUrl + "account/register?returnUrl=" + encodeURIComponent(app.rootUrl + "audiobook/" + this.workId);
            this.loadPreviousChapter = function () {
                var ch = _this.previousChapter();
                if (ch) {
                    _this.loadChapter(ch);
                }
            };
            this.loadNextChapter = function () {
                var ch = _this.nextChapter();
                if (ch) {
                    _this.loadChapter(ch);
                }
            };
            this.constRewindStep = 30; // шаг перемотки
            this.backwardBtn = function () {
                _this.audio.currentTime -= _this.constRewindStep;
            };
            this.forwardBtn = function () {
                _this.audio.currentTime += _this.constRewindStep;
            };
            this.togglePlay = function () {
                var playing = !_this.audioPlaying();
                var playAudio = function () {
                    var playPromise = _this.audio.play();
                    // In browsers that don’t yet support this functionality, playPromise won’t be defined.
                    if (playPromise) {
                        playPromise.catch(function (error) {
                            console.error("Audio error: ", error);
                            var time = _this.audio.currentTime;
                            var src = _this.audio.src;
                            _this.audio.src = null;
                            _this.audio.src = src;
                            _this.audio.currentTime = time;
                        });
                    }
                };
                if (playing) {
                    if (_this.adultOnly && !(app.isAuthenticated || cookieUtils_1.default.getAdultUser())) {
                        _this.showModal({
                            title: "\u0412\u0437\u0440\u043E\u0441\u043B\u044B\u0439 \u043A\u043E\u043D\u0442\u0435\u043D\u0442",
                            type: 0,
                            templateId: "adultOnlyModal",
                            viewModel: _this
                        });
                    }
                    else {
                        if (_this.firstPlay) {
                            $(".btn-pulse").removeClass("btn-pulse");
                            var currentChapter = _.find(_this.chapters, function (x) { return x.id === _this.options.chapterId; });
                            _this.currentChapter(currentChapter);
                            ajaxUtils_1.AjaxUtils.get(_this.s3url, { path: currentChapter.url })
                                .done(function (result) {
                                if (!result.isSuccessful) {
                                    alert(result.messages[0]);
                                    return;
                                }
                                _this.audio.src = result.data;
                                $("#href-tab-chapters").tab("show");
                                playAudio();
                            });
                        }
                        else {
                            playAudio();
                        }
                        _this.audioPlaying(playing);
                    }
                }
                else {
                    _this.audio.pause();
                    _this.updateReadingProgress();
                    _this.audioPlaying(playing);
                }
            };
            this.toggleAudioVolume = function () {
                if (_this.audioVolume() > 0) {
                    _this.savedVolume = _this.audioVolume();
                    _this.audioVolume(0);
                }
                else {
                    _this.audioVolume(_this.savedVolume);
                }
            };
            this.changeAudioSpeed = function (speed) {
                _this.audioSpeed(speed);
            };
            this.loadChapter = function (chapter) {
                _this.currentChapter(chapter);
                ajaxUtils_1.AjaxUtils.get(_this.s3url, { path: chapter.url })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    _this.audio.src = result.data;
                    _this.audio.play();
                    _this.chapterProgress(0);
                    _this.$timelineSeek.val(0);
                    _this.updateReadingProgress();
                });
            };
            this.getTimeCode = function (num) {
                if (isNaN(num))
                    return "00:00";
                var seconds = Math.floor(num);
                var hours = Math.floor(seconds / 3600);
                var minutes = Math.floor((seconds - (hours * 3600)) / 60);
                seconds = seconds - (hours * 3600) - (minutes * 60);
                if (minutes < 10) {
                    minutes = "0" + minutes;
                }
                if (seconds < 10) {
                    seconds = "0" + seconds;
                }
                var result;
                if (hours > 0) {
                    if (hours < 10) {
                        hours = "0" + hours;
                    }
                    result = hours + ":" + minutes + ":" + seconds;
                }
                else {
                    result = minutes + ":" + seconds;
                }
                return result;
            };
            this.downloadFile = function (chapterId, viewModel, event) {
                if (!app.ensureAuth())
                    return;
                var $button = $(event.currentTarget);
                $button.attr("disabled", "disabled").addClass("is-loading");
                $.get(window["app"].rootUrl + "audiobook/download", { chapterId: chapterId })
                    .done(function (result) {
                    if (result.isSuccessful) {
                        window.location = result.data;
                    }
                })
                    .always(function () {
                    $button.removeAttr("disabled").removeClass("is-loading");
                });
            };
            this.statsInit = false;
            this.workStatLoaded = ko.observable(false);
            this.totalCount = ko.observable(0);
            this.readingCount = ko.observable(0);
            this.savedCount = ko.observable(0);
            this.finishedCount = ko.observable(0);
            this.dislikedCount = ko.observable(0);
            this.timelineLoaded = ko.observable(false);
            this.timelineHtml = ko.observable();
            this.chapters = options.chapters;
            socialUtils_1.default.init();
            richContentUtils_1.default.processHtml(".annotation");
            localStorageUtils_1.default.addToList(localStorageUtils_1.default.RecentlyViewedKey, this.workId);
            this.booktrailerVideoUrl(options.booktrailerVideoUrl);
            this.showFullStats(options.showFullStats);
            this.loadSettings();
            this.initAudioPlayer();
            this.loadComments(null, null, false);
            this.adultOnly = options.adultOnly;
        }
        ViewModel.prototype.loadSettings = function () {
            var _this = this;
            var settings = localStorageUtils_1.default.get("audio.settings");
            if (settings === null || settings === undefined) {
                settings = {
                    volume: 1,
                    speed: 1,
                    version: "1.0"
                };
            }
            this.audioVolume(settings.volume || 1);
            this.audioSpeed(settings.speed || 1);
            this.audioVolume.subscribe(function () { return _this.saveSettings(); });
            this.audioSpeed.subscribe(function () { return _this.saveSettings(); });
        };
        ViewModel.prototype.saveSettings = function () {
            var settings = {
                volume: this.audioVolume(),
                speed: this.audioSpeed(),
                version: "1.0"
            };
            localStorageUtils_1.default.set("audio.settings", settings);
        };
        ViewModel.prototype.endOfAudio = function () {
            if (this.nextChapter()) {
                this.loadNextChapter();
                return;
            }
            if (this.chapters.length < this.options.totalChapterCount) {
                var messageText = void 0;
                if (app.isAuthenticated) {
                    messageText =
                        "<p>Книга находится в платном доступе.</p><p>Чтобы продолжить, пожалуйста, оплатите доступ.</p>";
                }
                else {
                    messageText = "<p>Книга находится в платном доступе.</p>" +
                        "<p>Чтобы продолжить слушать аудиокнигу, пожалуйста, <a onclick=\"viewModel.modal.hide();app.showLoginModal();\">войдите в свой аккаунт<a/> на Author.Today " +
                        ("\u0438\u043B\u0438 <a href=\"" + this.registerUrl + "\">\u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044C<a/>.</p>");
                }
                this.showModal({
                    title: "\u041A\u043E\u043D\u0435\u0446 \u043E\u0437\u043D\u0430\u043A\u043E\u043C\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442\u0430",
                    type: 3,
                    message: messageText
                });
            }
            this.audio.pause();
            this.audioPlaying(false);
        };
        ViewModel.prototype.initAudioPlayer = function () {
            var _this = this;
            this.audio = new Audio();
            this.$timelineSeek = $("#timelineSeek");
            $(this.audio)
                .on("loadedmetadata", function () {
                console.info("Audio: loadedmetadata");
                _this.chapterDuration(_this.audio.duration);
            })
                .on("loadeddata", function () {
                console.info("Audio: loadeddata");
                if (_this.firstPlay) {
                    _this.firstPlay = false;
                    $(".btn-pulse").removeClass("btn-pulse");
                    if (_this.options.chapterId === _this.currentChapter().id) {
                        _this.chapterProgress(_this.options.chapterProgress);
                        _this.audio.currentTime = _this.audio.duration * _this.options.chapterProgress / 100;
                    }
                    try {
                        metrikaUtils_1.default.reachGoal("startAudio", { from: "WorkPage" });
                    }
                    catch (ex) { }
                    ;
                    // запускаем подсчет метрики audio10Min
                    _this.metricsLastTick = new Date().getTime();
                    var spentTimeToCheck = 1000 * 60 * 10; // 10 минут
                    var checkSpentTimeInterval = setInterval(function () {
                        if (_this.metricsSpentTime > spentTimeToCheck) {
                            clearInterval(checkSpentTimeInterval);
                            try {
                                metrikaUtils_1.default.reachGoal("audio10Min", { from: "WorkPage" });
                            }
                            catch (ex) { }
                            ;
                        }
                    }, 2000);
                }
                _this.audio.volume = _this.audioVolume();
                _this.audio.playbackRate = _this.audioSpeed();
                if (_this.audio.currentTime === _this.audio.duration) {
                    _this.endOfAudio();
                }
            })
                .on("loadstart", function () {
                console.info("Audio: loadstart");
                _this.audioWaiting(true);
            })
                .on("waiting", function () {
                console.info("Audio: waiting");
                _this.audioWaiting(true);
            })
                .on("playing", function () {
                console.info("Audio: playing");
                _this.audioPlaying(true);
                _this.audioWaiting(false);
            })
                .on("timeupdate", function () {
                var progress = _this.audio.currentTime / _this.audio.duration * 100;
                if (!isNaN(progress)) {
                    _this.chapterCurrentTime(_this.audio.currentTime);
                    _this.chapterProgress(progress);
                    _this.$timelineSeek.val(progress * 10);
                }
                else {
                    _this.chapterCurrentTime(0);
                    _this.chapterProgress(0);
                }
                if (_this.metricsLastTick) {
                    var tick = new Date().getTime();
                    var delta = tick - _this.metricsLastTick;
                    if (delta < 1000) {
                        _this.metricsSpentTime += delta;
                    }
                    _this.metricsLastTick = tick;
                }
            })
                .on("ended", function () {
                console.info("Audio: ended");
                var endOfAudio = _this.audio.currentTime === _this.audio.duration;
                if (endOfAudio) {
                    _this.endOfAudio();
                }
                else {
                    _this.audioWaiting(true);
                }
            });
            this.audio.preload = "metadata";
            this.progressComputed.subscribe(function () {
                _this.updateReadingProgress();
            });
            this.$timelineSeek.on("input", function (e) {
                var progress = _this.$timelineSeek.val() / 10;
                _this.audio.currentTime = _this.audio.duration * progress / 100;
                _this.chapterProgress(progress);
            });
            var $volumeSeek = $("#volumeSeek");
            this.audioVolume.subscribe(function (volume) {
                _this.audio.volume = volume;
                $volumeSeek.val(volume * 100);
            });
            $volumeSeek.on("input", function (e) {
                _this.audioVolume($volumeSeek.val() / 100);
            });
            this.audioSpeed.subscribe(function (speed) {
                _this.audio.playbackRate = speed;
            });
            $(".chapter-available").each(function (i, el) {
                $(el).on("click", function (e) {
                    if ($(e.target).is(".chapter-download") ||
                        $(e.target).parents(".chapter-download").length)
                        return;
                    _this.loadChapter(_this.chapters[i]);
                });
            });
            if (location.hash === "#startAudio") {
                this.togglePlay();
            }
        };
        ViewModel.prototype.updateReadingProgress = function () {
            var data = {
                wId: this.workId,
                cId: this.currentChapter().id,
                wp: 0,
                cp: this.chapterProgress(),
                sId: this.options.sessionId
            };
            ajaxUtils_1.AjaxUtils.post(app.statsApiUrl + ("audiobook/update-progress?" + $.param(data)), null)
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
            });
        };
        ViewModel.prototype.showMaterialsTab = function () {
            $("#href-tab-maretials").tab("show");
            setTimeout(function () {
                if (!$("#masonry")[0])
                    return;
                var masonry = new Masonry("#masonry", {
                    itemSelector: "figure",
                    gutter: 10,
                    columnWidth: ".grid-sizer",
                    percentPosition: true
                });
                $("#masonry figure")["imagesLoaded"]()
                    .progress(function () {
                    masonry.layout();
                });
                $(window)
                    .on("resize", function () {
                    setTimeout(function () { return masonry.layout(); }, 200);
                });
                imageZoomUtils_1.default.initWorkMaterials();
            }, 200);
        };
        /** Загружает информацию для вкладки "Статистика" */
        ViewModel.prototype.showStatsTab = function () {
            var _this = this;
            $("#href-tab-stats").tab("show");
            if (this.statsInit)
                return;
            ajaxUtils_1.AjaxUtils.get("work/work-stats", { workId: this.workId })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.totalCount(result.data.totalCount);
                _this.readingCount(result.data.readingCount);
                _this.savedCount(result.data.savedCount);
                _this.finishedCount(result.data.finishedCount);
                _this.dislikedCount(result.data.dislikedCount);
            })
                .always(function () {
                _this.workStatLoaded(true);
            });
            if (this.showFullStats()) {
                scriptjs([ajaxUtils_1.AjaxUtils.getFullUrl("dist/js/amcharts?v=140717")], function () {
                    ko.computed(function () {
                        _this.isLoading(true);
                        _this.statsFilterData();
                        _this.loadDynamicChart();
                    });
                    _this.statsInit = true;
                });
            }
            else {
                this.statsInit = true;
            }
        };
        ViewModel.prototype.showTimelineTab = function () {
            var _this = this;
            $("#href-tab-timeline").tab("show");
            if (this.timelineLoaded())
                return;
            ajaxUtils_1.AjaxUtils.get("work/timeline", { id: this.workId })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.timelineHtml(result.data.html);
                setTimeout(function () {
                    var $timeline = $("#tab-timeline").find(".widget-content");
                    $timeline.addClass("in");
                    dateTimeUtils_1.default.displayTime($timeline);
                }, 0);
            })
                .always(function () {
                _this.timelineLoaded(true);
            });
        };
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/user-activity-data", this.statsFilterData())
                .done(function (result) {
                var daysInPerios = Math.floor((_this.endDate() - _this.startDate()) / (1000 * 60 * 60 * 24));
                var minPeriod = "DD";
                var categoryBalloonDateFormat = "MMMM DD, YYYY";
                if (daysInPerios > 40) {
                    minPeriod = "MM";
                    categoryBalloonDateFormat = "MMMM, YYYY";
                }
                _this.dynamicChart = AmCharts.makeChart("statsChartdiv", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    valueAxes: [
                        {
                            id: "countAxis",
                            axisAlpha: 0,
                            position: "left",
                            integersOnly: true,
                            title: "Количество просмотров"
                        }, {
                            title: "Время прослушивания, часы",
                            id: "durationAxis",
                            axisAlpha: 0,
                            gridAlpha: 0,
                            position: "right"
                        }
                    ],
                    graphs: [
                        {
                            balloonText: "Просмотров: [[value]]",
                            fillAlphas: 0.7,
                            legendValueText: "[[value]]",
                            type: "column",
                            valueField: "totalViewCount",
                            valueAxis: "countAxis"
                        }, {
                            balloonText: "Время прослушивания: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]] ч.",
                            fillAlphas: 0,
                            valueField: "spentTime",
                            valueAxis: "durationAxis"
                        }
                    ],
                    chartCursor: {
                        categoryBalloonDateFormat: categoryBalloonDateFormat,
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        valueBalloonsEnabled: false,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY",
                    categoryField: "date",
                    categoryAxis: {
                        parseDates: true,
                        dashLength: 1,
                        minorGridEnabled: true,
                        minPeriod: minPeriod
                    },
                    legend: {
                        equalWidths: false,
                        useGraphSettings: true,
                        align: "center"
                    },
                    dataProvider: result.data,
                    pathToImages: window["app"].rootUrl + "dist/vendor/amcharts/images/"
                });
                _this.isLoading(false);
            });
        };
        ViewModel.prototype.updateATRecState = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateATRecomendation", {
                id: this.workId,
                isATRecommended: !this.isATRecommended
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        ViewModel.prototype.setAdultCookie = function () {
            cookieUtils_1.default.setAdultUser();
            this.modal.hide();
            this.togglePlay();
        };
        ViewModel.prototype.updateBiblioNightState = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateBiblioNight", {
                id: this.workId,
                isBiblioNight: !this.isBiblioNight
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        return ViewModel;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/cookieUtils":51,"../utils/dateTimeUtils":52,"../utils/imageZoomUtils":57,"../utils/localStorageUtils":59,"../utils/metrikaUtils":61,"../utils/richContentUtils":67,"../utils/socialUtils":68,"./commentsView":99,"imagesloaded":212,"jquery":214,"knockout":191,"lodash":216,"masonry-layout":217,"moment":219,"numeral":220,"scriptjs":194}],91:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.ranges = {
                'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")]
            };
            this.dateRangePickerOptions = {
                minDate: moment().startOf("day").add(-30, "days"),
                maxDate: moment()
            };
            this.startDate = ko.observable();
            this.endDate = ko.observable();
            this.isLoading = ko.observable(true);
            this.getFilterData = function () {
                return _this.filterData();
            };
            this.type = options.type;
            this.auId = options.auId;
            this.routeName = options.routeName;
            this.startDate(options.startDate ? moment(options.startDate) : moment().startOf("day").add(-6, "days"));
            this.endDate(options.endDate ? moment(options.endDate) : moment().endOf("day"));
            this.filterData = ko.computed(function () {
                var filterData = {
                    startDate: _this.toDateFormat(_this.startDate()),
                    endDate: _this.toDateFormat(_this.endDate()),
                    auId: _this.auId,
                    type: 2
                };
                return filterData;
            }).extend({
                rateLimit: {
                    timeout: 300,
                    method: "notifyWhenChangesStop"
                }
            });
            var isInitialized = false;
            setTimeout(function () {
                ko.computed(function () {
                    var data = _this.filterData();
                    if (!isInitialized)
                        return;
                    _this.isLoading(true);
                    _this.loadDynamicChart();
                    var grid = $("#grid").data("kendoGrid");
                    if (grid) {
                        grid.dataSource.read(data);
                    }
                    try {
                        if (!data.auId || data.auId === "null") {
                            delete data.auId;
                        }
                        history.replaceState(null, null, "author-rating?" + $.param(data));
                    }
                    catch (e) {
                    }
                });
            });
            this.filterData.subscribe(function () {
                isInitialized = true;
            });
        }
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/merged-by-day", this.filterData())
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                AmCharts.makeChart("chartdiv", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    synchronizeGrid: true,
                    thousandsSeparator: " ",
                    "categoryField": "date",
                    "categoryAxis": {
                        gridPosition: "start",
                        parseDates: true,
                        dashLength: 1,
                        minPeriod: "DD"
                    },
                    "graphs": [
                        {
                            "title": "Рейтинг",
                            "valueField": "value",
                            "lineColor": "#80c858",
                            "negativeLineColor": "#a94442",
                            "fillAlphas": 0.4,
                            "type": "smoothedLine"
                        }
                    ],
                    "valueAxes": [
                        {
                            "title": "Авторский рейтинг"
                        }
                    ],
                    "legend": {
                        "useGraphSettings": true
                    },
                    "dataProvider": result.data,
                    chartCursor: {
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY"
                });
                _this.isLoading(false);
            });
        };
        ViewModel.prototype.toDateFormat = function (date) {
            return date.toISOString();
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191,"moment":219}],92:[function(require,module,exports){
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var BaseViewModel = (function () {
        function BaseViewModel(options) {
            this.successMessage = ko.observable();
            this.errorMessages = ko.observableArray();
            this.options = options;
            if (options) {
                if (options.successMessage) {
                    toastr.success(options.successMessage);
                }
                if (options.errorMessage) {
                    toastr.error(options.errorMessage);
                }
            }
        }
        BaseViewModel.prototype.fullReloadPage = function () {
            window.location.reload(true);
        };
        BaseViewModel.prototype.reloadPage = function (fragment) {
            if (fragment) {
                $.pjax.reload(fragment, { fragment: fragment });
            }
            else {
                $.pjax.reload("#pjax-container");
            }
        };
        BaseViewModel.prototype.redirectToPage = function (url, container) {
            if (container === void 0) { container = "#pjax-container"; }
            $.pjax({ url: url, container: container });
        };
        BaseViewModel.prototype.forceRedirectToPage = function (url) {
            window.location = url;
        };
        BaseViewModel.prototype.showModal = function (options) {
            var component = window["AppComponents"].ModalDialog;
            this.modal = component;
            this.modal.show(options);
        };
        return BaseViewModel;
    }());
    exports.BaseViewModel = BaseViewModel;
});

},{"jquery":214,"knockout":191,"toastr":199}],93:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "knockout.validation", "./baseViewModel", "../../utils/ajaxUtils", "toastr", "../../utils/windowUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validation = require("knockout.validation");
    var baseViewModel_1 = require("./baseViewModel");
    var ajaxUtils_1 = require("../../utils/ajaxUtils");
    var toastr = require("toastr");
    var windowUtils_1 = require("../../utils/windowUtils");
    validation.init({
        insertMessages: true,
        decorateInputElement: true,
        decorateElement: true,
        messagesOnModified: false,
        errorElementClass: "has-error",
        errorMessageClass: "help-inline error"
    }, true);
    validation.localize({
        required: "Необходимо заполнить это поле.",
        min: "Значение должно быть больше или равно {0}.",
        max: "Значение должно быть меньше или равно {0}.",
        minLength: "Длина поля должна быть не меньше {0} символов.",
        maxLength: "Длина поля должна быть не больше {0} символов.",
        pattern: "Пожалуйста проверьте это поле.",
        step: "Значение поле должно изменяться с шагом {0}",
        email: "Введите в поле правильный адрес email",
        date: "Пожалуйста введите правильную дату",
        dateISO: "Пожалуйста введите правильную дату в формате ISO",
        number: "Поле должно содержать число",
        digit: "Поле должно содержать цифры",
        phoneUS: "Поле должно содержать правильный номер телефона",
        equal: "Значения должны быть равны",
        notEqual: "Пожалуйста выберите другое значение.",
        unique: "Значение должно быть уникальным."
    });
    var ValidatedViewModel = (function (_super) {
        __extends(ValidatedViewModel, _super);
        function ValidatedViewModel(options) {
            _super.call(this, options);
            this.processing = ko.observable(false);
        }
        ValidatedViewModel.prototype.initValidation = function () {
            this.validation = ko.validatedObservable(this);
        };
        ValidatedViewModel.prototype.submit = function (formElement, extendedData) {
            var _this = this;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            ;
            if (this.processing())
                return;
            this.beforeSubmit(formElement, extendedData, function () {
                return ajaxUtils_1.AjaxUtils.submit(formElement, extendedData)
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        _this.errorMessages(result.messages);
                        if (result.data && result.data.stackTrace !== undefined) {
                            console.error(result.data.stackTrace);
                        }
                        _this.onSubmitFail(result, formElement);
                    }
                    else {
                        if (result.messages && result.messages.length > 0) {
                            toastr.success(result.messages[0]);
                        }
                        windowUtils_1.default.setDirty(false);
                        _this.onSubmitSucess(result, formElement);
                    }
                })
                    .fail(function () {
                    toastr.error("Произошла ошибка. Пожалуйста, повторите операцию еще раз или сообщите об этом в службу поддержки.");
                })
                    .always(function () {
                    setTimeout(function () {
                        _this.processing(false);
                    }, 0);
                });
            });
        };
        ValidatedViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            this.processing(true);
            this.errorMessages([]);
            callback();
        };
        ValidatedViewModel.prototype.onSubmitSucess = function (result, formElement) {
            // override this
        };
        ValidatedViewModel.prototype.onSubmitFail = function (result, formElement) {
            // override this
        };
        return ValidatedViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ValidatedViewModel;
});

},{"../../utils/ajaxUtils":45,"../../utils/windowUtils":72,"./baseViewModel":92,"knockout":191,"knockout.validation":190,"toastr":199}],94:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.genres = ko.observableArray();
            this.exceptGenreIds = ko.observableArray();
            this.form = ko.observable();
            this.state = ko.observable();
            this.series = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.viewMode = ko.observable();
            this.hideFinished = ko.observable(false);
            this.favoriteFilter = ko.observable();
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var genres = _this.genres(), exceptGenreIds = _this.exceptGenreIds(), form = _this.form(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), favoriteFilter = _this.favoriteFilter(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), view = _this.viewMode(), fnd = _this.hideFinished(), rp = _this.rp();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (options.sorting !== "random") {
                    params.sorting = options.sorting;
                }
                if (form !== "any") {
                    params.form = form;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (format !== "any") {
                    params.format = format;
                }
                if (duration !== "any") {
                    params.duration = duration;
                }
                if (length !== "any") {
                    params.length = length;
                }
                if (favoriteFilter !== "any") {
                    params.favoriteFilter = favoriteFilter;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (rp != "today") {
                    params.rp = rp;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                params.fnd = fnd;
                var genreCodes;
                if (genres && genres.length > 0) {
                    genreCodes = genres.join("&");
                }
                else {
                    genreCodes = "all";
                }
                var url = app.rootUrl + ("promo/black-friday/" + genreCodes + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],95:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./collectionView", "../utils/richContentUtils", "../utils/commentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var collectionView_1 = require("./collectionView");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var commentUtils_1 = require("../utils/commentUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.commentSubscription = ko.observable();
            commentUtils_1.default.init(options.lastViewTime);
            richContentUtils_1.default.processHtml(".comments");
        }
        return ViewModel;
    }(collectionView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/commentUtils":49,"../utils/richContentUtils":67,"./collectionView":98,"knockout":191}],96:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/imageUtils", "../components/modalDialog", "../utils/windowUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var imageUtils_1 = require("../utils/imageUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var windowUtils_1 = require("../utils/windowUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 100;
            this.descriptionMaxLength = 2000;
            this.uploadErrorMessages = ko.observableArray();
            this.title = ko.observable().extend({
                required: true,
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                return title.length + "/" + _this.titleMaxLength;
            });
            this.description = ko.observable().extend({
                required: {
                    params: true,
                    message: "Необходимо заполнить это поле."
                }
            });
            this.descriptionHint = ko.pureComputed(function () {
                var description = _this.description() || "";
                return description.length + "/" + _this.descriptionMaxLength;
            });
            this.tags = ko.observableArray(this.options.tags || []).extend({
                maxLength: { params: 9, message: "Нужно указать не более 9-ти тэгов" }
            });
            this.tagsSelect2Settings = {
                placeholder: 'До 9 тэгов через запятую...',
                tags: true, ajax: {
                    url: window["app"].rootUrl + "collection/searchTags",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [','],
                maximumSelectionLength: 9,
                language: {
                    maximumSelected: function () { return 'Вы можете выбрать не более 9 тэгов.'; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    item.count = item.count || 0;
                    var markup = "<div class='clearfix'>\
                <div class='pull-left'>" + item.text + "</div>\
                <div class='pull-right'>" + item.count + "<div>\
                </div>";
                    return markup;
                }
            };
            this.privacyCommentsId = ko.observable();
            this.privacyCommentsOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.coverUrl = ko.observable();
            this.id = options.id;
            this.privacyCommentsId(options.privacyCommentsId);
            this.titleInit = options.titleInit;
            this.descriptionInit = options.descriptionInit;
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            ko.computed(function () {
                var title = _this.title() || "";
                var description = _this.description() || "";
                if (stringUtils_1.default.compareWithoutLineBreaks(description, _this.descriptionInit)
                    || stringUtils_1.default.compareWithoutLineBreaks(title, _this.titleInit)) {
                    windowUtils_1.default.setDirty();
                }
                else {
                    windowUtils_1.default.setDirty(false);
                }
            });
        }
        ViewModel.prototype.selectImage = function () {
            var $input = this.modal.getModal().find("input[type='file']");
            $input.click();
        };
        ViewModel.prototype.showUploadCoverModal = function () {
            var _this = this;
            this.showModal({
                title: "Загрузка изображения",
                type: modalDialog_1.ModalType.Custom,
                templateId: "uploadCover",
                onShow: function ($modal) {
                    _this.uploadErrorMessages([]);
                    var $dropZone = $modal.find((".drop-zone"));
                    imageUtils_1.default.createDropZone($dropZone, function (files) {
                        _this.processFiles(files);
                    });
                }
            });
        };
        ViewModel.prototype.removeCover = function () {
            URL.revokeObjectURL(this.coverUrl());
            this.coverUrl(null);
        };
        ViewModel.prototype.onSelectImage = function (data, event) {
            this.uploadErrorMessages([]);
            var $input = $(event.target), files = event.target.files;
            this.processFiles(files);
            $input.val("");
        };
        ViewModel.prototype.processFiles = function (files) {
            var _this = this;
            if (files && files.length) {
                var file = files[0];
                if (file.size > 500 * 1024) {
                    this.uploadErrorMessages(["Слишком большой размер файла. Пожалуйста, выберите файл размером не более 500 кб."]);
                    return;
                }
                if (!/^image\/\w+$/.test(file.type)) {
                    this.uploadErrorMessages(["Данный формат файла не поддерживается. Пожалуйста, выберите изображение."]);
                    return;
                }
                var blobUrl = URL.createObjectURL(file);
                imageUtils_1.default.getImageSize(blobUrl).done(function (imageSize) {
                    if (imageSize.width !== 1140 || imageSize.height !== 380) {
                        _this.uploadErrorMessages(["Неправильный размер изображения."]);
                        return;
                    }
                    _this.coverUrl(blobUrl);
                    _this.coverUrlFile = file;
                    _this.modal.hide();
                });
            }
        };
        ViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            if (this.coverUrlFile) {
                var formData = new FormData();
                formData.append("file", this.coverUrlFile);
                ajaxUtils_1.AjaxUtils.uploadFile("file/uploadCollectionCoverImage", formData)
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        _this.errorMessages(result.messages);
                    }
                    else {
                        _this.coverUrl(result.data.url);
                        setTimeout(callback, 50);
                    }
                }).fail(function () {
                    _this.errorMessages(["Произошла ошибка во время загрузки изображения. Попробуйте еще раз через некоторое время."]);
                    _this.processing(false);
                });
            }
            else {
                callback();
            }
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data && result.data.redirectUrl) {
                this.redirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/imageUtils":56,"../utils/stringUtils":69,"../utils/windowUtils":72,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216}],97:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "drop", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/windowUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var Drop = require("drop");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var windowUtils_1 = require("../utils/windowUtils");
    var Work = (function () {
        function Work(options) {
            var _this = this;
            this.commentTextMaxLength = 1000;
            this.commentText = ko.observable("");
            this.isEditing = ko.observable(false);
            this.commentTextHint = ko.pureComputed(function () {
                var commentText = _this.commentText() || "";
                return commentText.length + "/" + _this.commentTextMaxLength;
            });
            this.startEditing = function () {
                _this.originalCommentText = _this.commentText();
                _this.isEditing(true);
            };
            this.cancelEditing = function () {
                _this.commentText(_this.originalCommentText);
                _this.isEditing(false);
            };
            this.save = function () {
                ajaxUtils_1.AjaxUtils.post("collection/updateWork", {
                    workCollectionId: _this.workCollectionId,
                    commentText: _this.commentText()
                }).done(function (result) {
                    if (result.isSuccessful) {
                        toastr.success(result.messages[0]);
                        _this.isEditing(false);
                    }
                    else {
                        alert(result.messages[0]);
                    }
                });
            };
            this.id = options.id;
            this.title = options.title;
            this.coverUrl = options.coverUrl;
            this.authorFIO = options.authorFIO;
            this.coAuthorFIO = options.coAuthorFIO;
            this.commentText(options.commentText);
            this.workCollectionId = options.workCollectionId;
            this.isSaved = !!this.workCollectionId;
        }
        return Work;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.worksToAdd = ko.observableArray([]);
            this.worksInCollection = ko.observableArray([]);
            this.currentSortIndex = ko.observable();
            this.newSortIndex = ko.observable();
            this.enableSorting = ko.observable();
            this.isEnableSortingToggled = false;
            this.workId = ko.observable();
            this.workIdSearchSelect2Settings = {
                minimumResultsForSearch: 5,
                minimumInputLength: 2,
                placeholder: "Добавить произведение",
                ajax: {
                    url: window["app"].rootUrl + "work/searchWorks",
                    dataType: "json",
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            exceptCollection: _this.id,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            return result.data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    var markup = "<div class='work'>" + (item.coverUrl ? "<img src='" + item.coverUrl + "' class='work-cover'/>" : "") + "<span>" + item.title + "</span></div>";
                    return markup;
                }
            };
            this.addType = ko.observable("Append");
            this.removeWorkFromList = function (work) {
                if (!work.isSaved) {
                    _this.worksToAdd.remove(work);
                    return;
                }
                _this.showModal({
                    title: "Удаление произведения",
                    message: "Вы точно хотите удалить это произведение из подборки?",
                    onSubmit: function () {
                        return ajaxUtils_1.AjaxUtils.post("collection/deleteWork", {
                            workCollectionId: work.workCollectionId
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                _this.worksInCollection.remove(work);
                                toastr.success(result.messages[0]);
                            }
                            else {
                                alert(result.messages[0]);
                            }
                        });
                    }
                });
            };
            this.moveToIndex = function (currentIndex, newIndex) {
                if (_this.processing())
                    return;
                var offsetIndex = _this.addType() === 'Prepend' ? _this.worksToAdd().length : 0, newIndexVal = newIndex - offsetIndex, currentIndexVal = currentIndex - offsetIndex;
                if (isNaN(newIndexVal) || newIndexVal < 0 || isNaN(currentIndexVal) || currentIndexVal < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndexVal === currentIndexVal) {
                    _this.closeAllDrop();
                    return;
                }
                var reload = newIndexVal >= (_this.worksInCollection().length + _this.startFrom) || newIndexVal < _this.startFrom;
                _this.reoderWorks(newIndexVal, currentIndexVal, function () {
                    if (reload) {
                        _this.reloadPage();
                    }
                    else {
                        ko.utils["moveTo"].call(_this.worksInCollection, currentIndexVal - _this.startFrom, newIndexVal - _this.startFrom);
                    }
                });
            };
            this.moveTo = function () {
                if (_this.processing())
                    return;
                var offsetIndex = _this.addType() === 'Prepend' ? _this.worksToAdd().length : 0, newIndex = _this.newSortIndex() - 1 - offsetIndex, currentIndex = _this.currentSortIndex() - offsetIndex;
                if (isNaN(newIndex) || newIndex < 0 || isNaN(currentIndex) || currentIndex < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndex === currentIndex) {
                    _this.closeAllDrop();
                    return;
                }
                var reload = newIndex >= (_this.worksInCollection().length + _this.startFrom) || newIndex < _this.startFrom;
                _this.reoderWorks(newIndex, currentIndex, function () {
                    if (reload) {
                        _this.reloadPage();
                    }
                    else {
                        ko.utils["moveTo"].call(_this.worksInCollection, currentIndex - _this.startFrom, newIndex - _this.startFrom);
                    }
                });
            };
            this.moveUp = function (index, work) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                if (_this.addType() === "Append") {
                    index += _this.startFrom;
                }
                else {
                    index += _this.worksToAdd().length;
                }
                var newIndex = index, reload = false;
                if (index === 0) {
                    newIndex = _this.options.totalCount - 1;
                    reload = _this.otherPagesCount > 0;
                }
                else {
                    if (index === _this.startFrom) {
                        reload = _this.otherPagesCount > 0;
                    }
                    newIndex--;
                }
                _this.reoderWorks(newIndex, index, function () {
                    if (reload) {
                        _this.reloadPage();
                    }
                    else {
                        ko.utils["moveUp"].call(_this.worksInCollection, work);
                    }
                });
            };
            this.moveDown = function (index, work) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                if (_this.addType() === "Append") {
                    index += _this.startFrom;
                }
                else {
                    index += _this.worksToAdd().length;
                }
                var newIndex = index, reload = false;
                if (index === _this.totalCount - 1) {
                    newIndex = 0;
                    reload = _this.otherPagesCount > 0;
                }
                else {
                    newIndex++;
                }
                _this.reoderWorks(newIndex, index, function () {
                    if (reload) {
                        _this.reloadPage();
                    }
                    else {
                        ko.utils["moveDown"].call(_this.worksInCollection, work);
                    }
                });
            };
            this.addWorks = function () {
                _this.processing(true);
                var works = _.map(_this.worksToAdd(), function (x) { return { id: x.id, commentText: x.commentText() }; });
                windowUtils_1.default.setDirty(false);
                ajaxUtils_1.AjaxUtils.post("collection/addWorks", {
                    collectionId: _this.id,
                    works: works,
                    addType: _this.addType()
                }).done(function (result) {
                    if (result.isSuccessful) {
                        _this.reloadPage();
                        toastr.success(result.messages[0]);
                    }
                    else {
                        windowUtils_1.default.setDirty(_this.worksToAdd().length > 0);
                        alert(_this.errorMessages[0]);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            };
            this.id = options.id;
            this.worksInCollection(_.map(options.works, function (x) { return new Work(x); }));
            this.totalCount = options.totalCount;
            this.otherPagesCount = options.totalCount - options.works.length;
            this.startFrom = options.startFrom;
            this.currentPage = options.currentPage;
            $(document).off("submit", "form[data-pjax]");
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                return false;
            });
            var self = this;
            $('#search-results').on('pjax:success', function () {
                self.initChangeOrderDrodown();
                windowUtils_1.default.setDirty(self.worksToAdd().length > 0);
            });
            $('#search-results').on('pjax:beforeSend', function (event, xhr, options) {
                windowUtils_1.default.setDirty(false);
                if (self.isEnableSortingToggled) {
                    options.url += "&page=" + _this.currentPage;
                    self.isEnableSortingToggled = false;
                }
            });
            setTimeout(function () {
                _this.enableSorting.subscribe(function () {
                    _this.isEnableSortingToggled = true;
                    $(".search-form").submit();
                });
            }, 200);
            this.enableSorting(options.enableSorting);
            $("#workSearch").on("select2:select", function (e) {
                _this.worksToAdd.push(new Work(e.params.data));
                $("#workSearch").val(null);
                $("#workSearch").trigger("change");
            });
            this.initChangeOrderDrodown();
            ko.computed(function () {
                var worksToAdd = _this.worksToAdd();
                if (worksToAdd.length > 0) {
                    windowUtils_1.default.setDirty();
                }
                else {
                    windowUtils_1.default.setDirty(false);
                }
            });
        }
        ViewModel.prototype.publish = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("collection/publish", {
                id: this.id
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                    toastr.success(result.messages[0]);
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.reoderWorks = function (newIndex, oldIndex, callback) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("collection/reoderWorks", {
                collectionId: this.id,
                newIndex: newIndex,
                oldIndex: oldIndex
            }).done(function (result) {
                if (result.isSuccessful) {
                    _this.closeAllDrop();
                    toastr.success(result.messages[0]);
                    callback();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.initChangeOrderDrodown = function () {
            var _this = this;
            var changeOrderDrodown = document.getElementById("work-order-dropdown").innerHTML;
            setTimeout(function () {
                $(".book-row").each(function (i, el) {
                    var $el = $(el), $changeOrderBtn = $el.find(".change-order-btn");
                    if (!$changeOrderBtn.length) {
                        return;
                    }
                    var drop = new Drop({
                        target: $changeOrderBtn[0],
                        content: function () {
                            var $content = $("<div />").html(changeOrderDrodown);
                            ko.applyBindingsToDescendants(_this, $content[0]);
                            return $content[0];
                        },
                        /*openOn: "hover",*/
                        hoverCloseDelay: 150,
                        constrainToScrollParent: true,
                        tetherOptions: {
                            attachment: "top center",
                            targetAttachment: "bottom center",
                            constraints: [
                                {
                                    to: "window",
                                    attachment: "together",
                                    pin: true
                                }
                            ]
                        }
                    });
                    drop.on("open", function () {
                        var order = JSON.parse($el.attr("data-order"));
                        _this.currentSortIndex(order);
                        _this.newSortIndex(order + 1);
                        drop.position();
                    });
                    $changeOrderBtn.data("drop", drop);
                });
            }, 0);
        };
        ViewModel.prototype.showMoveToDraftModal = function () {
            var _this = this;
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
                type: 2,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u0434\u0431\u043E\u0440\u043A\u0443 \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0438?",
                onSubmit: function () {
                    _this.processing(true);
                    return ajaxUtils_1.AjaxUtils.post("collection/moveToDraft", {
                        id: _this.id
                    }).done(function (result) {
                        _this.processing(false);
                        if (result.isSuccessful) {
                            _this.reloadPage();
                            toastr.success(result.messages[0]);
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.showDeleteCollectionModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление подборки",
                message: "Вы точно хотите удалить эту подборку?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("collection/delete", {
                        id: _this.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.closeAllDrop = function () {
            var drop = $(".drop-enabled").data("drop");
            if (drop) {
                drop.close();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../utils/ajaxUtils":45,"../utils/windowUtils":72,"./base/validatedViewModel":93,"drop":197,"jquery":214,"knockout":191,"lodash":216,"toastr":199}],98:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "../utils/socialUtils", "./commentsView"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var socialUtils_1 = require("../utils/socialUtils");
    var commentsView_1 = require("./commentsView");
    var Clipboard = require("clipboard");
    var CollectionViewModelBase = (function (_super) {
        __extends(CollectionViewModelBase, _super);
        function CollectionViewModelBase(options) {
            var _this = this;
            _super.call(this, options);
            this.collectionId = this.options.collectionId;
            this.isATRecommended = this.options.isATRecommended;
            this.processing = ko.observable(false);
            this.isLoading = ko.observable(false);
            this.exceptMyLibrary = ko.observable(this.options.eml);
            var initialized = false;
            socialUtils_1.default.init();
            var clipboard = new Clipboard("button[data-clipboard]", {
                text: function (el) { return $(el).attr("data-clipboard"); }
            });
            clipboard.off("sucess");
            clipboard.on("success", function (e) {
                var $el = $(e.trigger);
                $el.attr("data-hint-prev", $el.attr("data-hint"))
                    .attr("data-hint", "Ссылка скопирована")
                    .addClass("hint-always");
                setTimeout(function () {
                    $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                }, 3000);
            });
            clipboard.on("error", function (e) {
                var $el = $(e.trigger);
                var url = location.origin + $el.attr("data-clipboard");
                prompt("Чтобы скопировать ссылку на комментарий, нажмите Ctrl+C и потом Enter.", url);
            });
            $(".fox-welcome-1").on("click", function () {
                $(".fox-welcome-1").addClass("out");
                $(".fox-welcome-2").addClass("in");
                $(".fox-welcome-wrapper").css({ "padding-top": 270 });
                $("#foxAuth").fadeIn();
            });
            setTimeout(function () {
                $(".fox-welcome-wrapper").fadeIn();
            }, 200);
            this.loadComments(null, null, false);
            ko.computed(function () {
                var exceptMyLibrary = _this.exceptMyLibrary(), sorting = options.sorting, rp = options.rp;
                if (!initialized) {
                    return;
                }
                var params = {};
                if (sorting !== "default") {
                    params.sorting = sorting;
                }
                if (rp != "today") {
                    params.rp = rp;
                }
                if (exceptMyLibrary) {
                    params.eml = exceptMyLibrary;
                }
                var url = app.rootUrl + ("collection/" + _this.collectionId + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
            });
        }
        CollectionViewModelBase.prototype.updateATRecState = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("collection/updateATRecomendation", {
                id: this.collectionId,
                isATRecommended: !this.isATRecommended
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        return CollectionViewModelBase;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CollectionViewModelBase;
});

},{"../utils/ajaxUtils":45,"../utils/socialUtils":68,"./commentsView":99,"clipboard":202,"jquery":214,"knockout":191}],99:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/baseViewModel", "../utils/richContentUtils", "../utils/commentUtils", "../utils/commentLoadUtil", "../utils/imageZoomUtils", "../utils/dateTimeUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var commentUtils_1 = require("../utils/commentUtils");
    var commentLoadUtil_1 = require("../utils/commentLoadUtil");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    /** Отображение комментариев */
    var CommentsViewModel = (function (_super) {
        __extends(CommentsViewModel, _super);
        function CommentsViewModel(options) {
            _super.call(this, options);
            this.isSubscriptionChecked = ko.observable(null);
            this.subscriptionId = ko.observable();
            this.commentRootId = options.commentRootId;
            this.commentRootType = options.commentRootType;
        }
        /** Загрузка комментариев */
        CommentsViewModel.prototype.loadComments = function (paramsValue, thisObj, isReload) {
            var _this = this;
            if (paramsValue === void 0) { paramsValue = null; }
            if (thisObj === void 0) { thisObj = null; }
            if (isReload === void 0) { isReload = true; }
            if (!this.commentRootId) {
                return;
            }
            var errorContainer = $('#comment-error');
            errorContainer.hide();
            if (thisObj == null) {
                thisObj = this;
            }
            var commentContainer = $('#commentsAsync');
            commentContainer.empty();
            var spinner = $("#comments-spinner");
            spinner.show();
            var params;
            if (this.errorParams) {
                params = this.errorParams;
            }
            else {
                params = thisObj.getParams(paramsValue);
            }
            ajaxUtils_1.AjaxUtils.get("comment/load", { rootId: thisObj.commentRootId, rootType: thisObj.commentRootType, c: params.c, th: params.th, page: params.page, sorting: params.sorting })
                .done(function (result) {
                if (!result.isSuccessful) {
                    if (isReload) {
                        alert(result.messages[0]);
                        $("html,body").animate({ scrollTop: $("#comments").offset().top }, 350);
                    }
                    errorContainer.show();
                    _this.errorParams = params;
                    return;
                }
                _this.errorParams = null;
                commentContainer.html(result.data.html);
                $('#commentTotalCount').html(result.data.totalCount.toLocaleString('ru'));
                $('#commentPlural').html(stringUtils_1.default.pluralize(result.data.totalCount, ["комментарий", "комментария", "комментариев"]));
                ko.cleanNode(commentContainer[0]);
                ko.applyBindings(thisObj, commentContainer[0]);
                thisObj.initPagination();
                commentUtils_1.default.reInitNewComments();
                commentUtils_1.default.init(result.data.lastViewTime);
                commentUtils_1.default.initVotesInfo();
                dateTimeUtils_1.default.displayTime(commentContainer);
                richContentUtils_1.default.processHtml(".comments");
                imageZoomUtils_1.default.init(commentContainer[0]);
                if (thisObj.isSubscriptionChecked() == null) {
                    thisObj.subscriptionId(result.data.subscriptionId);
                    thisObj.isSubscriptionChecked(result.data.subscriptionId !== undefined
                        && result.data.subscriptionId !== null);
                    thisObj.loadSubscription();
                }
                if (isReload) {
                    setTimeout(function () {
                        $("html,body").animate({ scrollTop: $("#comments").offset().top }, 350);
                    }, 100);
                }
            })
                .always(function () {
                spinner.hide();
                commentLoadUtil_1.default.loaded(true);
            });
        };
        CommentsViewModel.prototype.loadSubscription = function () {
            var _this = this;
            setTimeout(function () {
                _this.isSubscriptionChecked.subscribe(function (value) {
                    if (value) {
                        ajaxUtils_1.AjaxUtils.post("comment/subscribe", {
                            rootId: _this.commentRootId,
                            rootTypeId: _this.commentRootType
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                toastr.success("Вы подписались на уведомления о новых комментариях.");
                                _this.subscriptionId(result.data);
                            }
                            else {
                                alert(result.messages[0]);
                            }
                        });
                    }
                    else {
                        ajaxUtils_1.AjaxUtils.post("comment/unsubscribe", {
                            id: _this.subscriptionId()
                        }).done(function (result) {
                            _this.subscriptionId(null);
                            if (result.isSuccessful) {
                                toastr.success("Вы отписались от уведомлений о новых комментариях.");
                            }
                            else {
                                alert(result.messages[0]);
                            }
                        });
                    }
                });
            }, 50);
        };
        /** Возвращает параметры в урле */
        CommentsViewModel.prototype.getParams = function (paramsValue) {
            if (paramsValue === void 0) { paramsValue = null; }
            if (!paramsValue) {
                paramsValue = location.search.replace('?', '');
            }
            var params = paramsValue.split('&');
            var c = null;
            var th = null;
            var page = null;
            var sorting = "reverse";
            for (var i = 0; i < params.length; i++) {
                var els = params[i].split('=');
                if (els[0] == "c") {
                    c = Number(els[1].split('#')[0]);
                }
                else if (els[0] == "th") {
                    th = Number(els[1].split('#')[0]);
                }
                else if (els[0] == "page") {
                    page = Number(els[1].split('#')[0]);
                }
                else if (els[0] == "sorting") {
                    sorting = els[1].split('#')[0];
                }
            }
            return { c: c, th: th, page: page, sorting: sorting };
        };
        /** Инициализация пагинации */
        CommentsViewModel.prototype.initPagination = function () {
            var thisObj = this;
            $('#commentsAsync .pagination li a').on("click", function () {
                var href = this.getAttribute("href");
                if (href) {
                    var paramsValue = this.getAttribute("href").split("?")[1];
                    thisObj.loadComments(paramsValue, thisObj);
                }
                return false;
            });
        };
        return CommentsViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CommentsViewModel;
});



},{"../utils/ajaxUtils":45,"../utils/commentLoadUtil":48,"../utils/commentUtils":49,"../utils/dateTimeUtils":52,"../utils/imageZoomUtils":57,"../utils/richContentUtils":67,"../utils/stringUtils":69,"./base/baseViewModel":92,"jquery":214,"knockout":191,"toastr":199}],100:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "lodash", "toastr", "../utils/ajaxUtils", "./base/baseViewModel", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var stringUtils_1 = require("../utils/stringUtils");
    var UserVote = (function () {
        function UserVote(options, groupCount, group, viewModel) {
            var _this = this;
            this.coAuthorUrl = null;
            this.vote = ko.observable();
            this.voteOptions = ko.observableArray();
            this.workId = options.workId;
            this.title = options.title;
            this.authorId = options.authorId;
            this.authorFIO = options.authorFIO;
            this.authorUserName = options.authorUserName;
            this.coAuthorId = options.coAuthorId;
            this.coAuthorFIO = options.coAuthorFIO;
            this.coAuthorUserName = options.coAuthorUserName;
            this.coAuthorConfirmed = options.coAuthorConfirmed;
            var rootUrl = window["app"].rootUrl;
            this.workUrl = rootUrl + "work/" + this.workId;
            this.readUrl = rootUrl + "reader/" + this.workId;
            this.authorUrl = rootUrl + "u/" + this.authorUserName;
            if (this.coAuthorId && this.coAuthorConfirmed) {
                this.coAuthorUrl = rootUrl + "u/" + this.coAuthorUserName;
            }
            this.vote(options.vote);
            this.groupCount = groupCount;
            this.group = group;
            this.viewModel = viewModel;
            setTimeout(function () {
                _this.vote.subscribe(function (newValue) {
                    ajaxUtils_1.AjaxUtils.post("contest/" + viewModel.contestId + "/selfJuryVote", {
                        contestId: viewModel.contestId,
                        groupId: _this.group.id,
                        workId: _this.workId,
                        vote: newValue
                    })
                        .done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success(result.messages[0]);
                        }
                        else {
                            toastr.error(result.messages[0]);
                        }
                    });
                });
            });
        }
        UserVote.prototype.init = function () {
            var _this = this;
            if (this.group.allMarksUnique) {
                _.each(this.group.works, function (w) {
                    if (w === _this)
                        return;
                    w.vote.subscribe(function () {
                        _this.recalculateOptions();
                    });
                });
                this.recalculateOptions();
            }
            else {
                this.voteOptions(this.group.availableMarks);
            }
        };
        UserVote.prototype.recalculateOptions = function () {
            var _this = this;
            var selectedOptions = _.map(this.group.works, function (w) {
                return w.vote();
            });
            var result = _.filter(this.group.availableMarks, function (v) {
                if (v === _this.vote())
                    return true;
                return _.indexOf(selectedOptions, v) === -1;
            });
            this.voteOptions(result);
        };
        return UserVote;
    }());
    var Group = (function () {
        function Group(options, viewModel) {
            var _this = this;
            this.works = [];
            this.worksToJuryCount = ko.observable();
            this.worksToJuryText = ko.observable();
            this.id = options.id;
            this.title = options.title;
            this.comment = options.comment;
            this.number = options.number;
            this.votingIsClosed = options.votingIsClosed;
            this.marks = options.marks;
            this.availableMarks = options.availableMarks;
            this.allMarksUnique = options.allMarksUnique;
            this.works = _.map(options.works, function (x) { return new UserVote(x, options.works.length, _this, viewModel); });
            this.viewModel = viewModel;
            _.each(this.works, function (w) {
                w.init();
                w.vote.subscribe(function () {
                    _this.updateWorksToJuryText();
                });
            });
            this.updateWorksToJuryText();
        }
        Group.prototype.updateWorksToJuryText = function () {
            var selectedOptions = _.filter(this.works, function (w) {
                return w.vote() !== null && w.vote() !== undefined;
            });
            var count = this.works.length - selectedOptions.length;
            this.worksToJuryCount(count);
            this.worksToJuryText(count + " " + stringUtils_1.default.pluralize(count, ["рассказ", "рассказа", "рассказов"]));
        };
        return Group;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.groups = [];
            this.contestId = options.contestId;
            this.groups = _.map(options.groups, function (x) { return new Group(x, _this); });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/stringUtils":69,"./base/baseViewModel":92,"knockout":191,"lodash":216,"toastr":199}],101:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.title = ko.observable().extend({
                required: true
            });
            this.marks = ko.observable().extend({
                required: true,
                pattern: {
                    message: "Введите диапазон оценок (1-10) или перечислите их через запятую (1,2,4,6)",
                    params: "^([0-9]+(-[0-9]+)?)(,([0-9]+(-[0-9]+)?))*$"
                }
            });
            this.marksAlgoritm = ko.observable();
            this.marksAlgoritmOptions = [
                { id: 1, title: "Среднее арифметическое" },
                { id: 2, title: "Сумма" }
            ];
            this.comment = ko.observable();
            this.id = options.id;
            this.marksAlgoritm = options.marksAlgoritm;
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.isSuccessful && result.data && result.data.redirectUrl) {
                this.forceRedirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        ViewModel.prototype.showDeleteModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление группы",
                message: "Вы точно хотите удалить эту группу?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("contest/group/delete", {
                        id: _this.id,
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                        else {
                            alert(result.messages[0]);
                            _this.modal.hide();
                        }
                    });
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"knockout":191}],102:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "jquery.countdown", "./base/validatedViewModel", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    require("jquery.countdown");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.itemId = ko.observable().extend({
                required: true
            });
            this.isParticipant = ko.observable();
            this.isParticipant(options.isParticipant);
            this.initValidation();
            window["moment"] = moment;
            if ($("#contest-countdown")[0]) {
                var labels = ["недель", "дней", "часов", "минут", "секунд"], nextYear = moment(options.nextStage).toDate(), template = _.template($("#countdown-template").html()), currDate = "00:00:00:00", nextDate = "00:00:00:00", parser = /([0-9]{2})/gi, $example = $("#contest-countdown");
                // Parse countdown string to an object
                var strfobj = function (str) {
                    var parsed = str.match(parser), obj = {};
                    labels.forEach(function (label, i) {
                        obj[label] = parsed[i];
                    });
                    return obj;
                };
                // Return the time components that diffs
                var diff = function (obj1, obj2) {
                    var diff = [];
                    labels.forEach(function (key) {
                        if (obj1[key] !== obj2[key]) {
                            diff.push(key);
                        }
                    });
                    return diff;
                };
                // Build the layout
                var initData = strfobj(currDate);
                labels.forEach(function (label, i) {
                    $example.append(template({
                        curr: initData[label],
                        next: initData[label],
                        label: label
                    }));
                });
                // Starts the countdown
                $example["countdown"](nextYear, function (event) {
                    var newDate = event.strftime("%w:%d:%H:%M:%S"), data;
                    if (newDate !== nextDate) {
                        currDate = nextDate;
                        nextDate = newDate;
                        // Setup the data
                        data = {
                            'curr': strfobj(currDate),
                            'next': strfobj(nextDate)
                        };
                        // Apply the new values to each node that changed
                        diff(data.curr, data.next).forEach(function (label) {
                            var selector = ".%s".replace(/%s/, label), $node = $example.find(selector);
                            // Update the node
                            $node.removeClass("flip");
                            $node.find(".curr").text(data.curr[label]);
                            $node.find(".next").text(data.next[label]);
                            // Wait for a repaint to then flip
                            _.delay(function ($node) {
                                $node.addClass("flip");
                            }, 50, $node);
                        });
                    }
                });
            }
        }
        ViewModel.prototype.showAddWorkModal = function () {
            this.showModal({
                title: "Подача заявки на конкурс",
                type: modalDialog_1.ModalType.Custom,
                templateId: "addItemModal",
                minWidth: "400px",
                maxWidth: "500px",
                viewModel: this
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.isParticipant(true);
            this.showModal({
                title: "Заявка принята",
                type: modalDialog_1.ModalType.Success,
                message: "Спасибо! Ваша заявка принята и будет рассмотрена администрацией.",
                maxWidth: "400px"
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../components/modalDialog":20,"./base/validatedViewModel":93,"jquery":214,"jquery.countdown":189,"knockout":191,"lodash":216,"moment":219}],103:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.contestId = options.contestId;
        }
        ViewModel.prototype.approve = function () {
            this.updateComplaints("approved");
        };
        ViewModel.prototype.reject = function () {
            this.updateComplaints("rejected");
        };
        ViewModel.prototype.updateComplaints = function (newStatus) {
            var grid = $("#grid").data("kendoGrid");
            var rows = grid.select();
            var requestData = {
                itemIds: [],
                status: newStatus
            };
            rows.each(function (index, row) {
                var selectedItem = grid.dataItem(row);
                requestData.itemIds.push(selectedItem.Id);
            });
            return ajaxUtils_1.AjaxUtils.post("contest/" + this.contestId + "/updateStatus", requestData)
                .done(function (result) {
                if (result.isSuccessful) {
                    grid.dataSource.read();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214}],104:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
        }
        ViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            var _this = this;
            this.errorMessages([]);
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
                type: 1,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0441\u043D\u044F\u0442\u044C \u0438\u043B\u043B\u044E\u0441\u0442\u0440\u0430\u0446\u0438\u044E \u0441 \u043A\u043E\u043D\u043A\u0443\u0440\u0441\u0430?",
                deleteBtnText: "Снять",
                onSubmit: function () {
                    _this.processing(true);
                    _this.modal.hide();
                    return callback();
                }
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.reloadPage();
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93}],105:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
        }
        ViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            var _this = this;
            this.errorMessages([]);
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
                type: 1,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0441\u043D\u044F\u0442\u044C \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0435 \u0441 \u043A\u043E\u043D\u043A\u0443\u0440\u0441\u0430?",
                deleteBtnText: "Снять",
                onSubmit: function () {
                    _this.processing(true);
                    _this.modal.hide();
                    return callback();
                }
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data.redirectUrl) {
                this.redirectToPage(result.data.redirectUrl);
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93}],106:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "toastr", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var toastr = require("toastr");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.handleSaveChanges = function (e) {
                setTimeout(function () {
                    $("#selfJuryGroups").data("kendoGrid").dataSource.read();
                }, 200);
            };
            this.handleGridError = function (e) {
                if (e.errors) {
                    var message = "Ошибки:\n";
                    $.each(e.errors, function (key, value) {
                        if ('errors' in value) {
                            $.each(value.errors, function () {
                                message += this + "<br>";
                            });
                        }
                    });
                    toastr.error(message);
                }
            };
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"jquery":214,"toastr":199}],107:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "./base/validatedViewModel", "../utils/ajaxUtils", "../components/modalDialog", "../utils/imageUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var imageUtils_1 = require("../utils/imageUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.title = ko.observable().extend({
                required: true
            });
            this.sponsor = ko.observable();
            this.sponsorOptions = [
                { id: 1, title: "Author.Today" },
                { id: 2, title: "Сообщество" }
            ];
            this.contestType = ko.observable();
            this.contestTypeOptions = [
                { id: 1, title: "Конкурс рассказов с самосудом" },
                { id: 2, title: "Конкурс рассказов анонимный" },
                { id: 3, title: "Конкурс романов и рецензий" },
                { id: 4, title: "Конкурс иллюстраций" },
                { id: 5, title: "Нестардартный конкурс" },
                { id: 5, title: "Нестардартный конкурс" }
            ];
            this.stageId = ko.observable();
            this.awardId = ko.observable();
            this.selectedAward = ko.pureComputed(function () {
                var id = _this.awardId();
                return _.find(_this.allAwards, function (x) {
                    return x.id === id;
                });
            });
            this.subTitle = ko.observable();
            this.previewText = ko.observable().extend({
                required: true
            });
            this.bottomTitle = ko.observable();
            this.showClock = ko.observable();
            this.nextStageDate = ko.observable().extend({
                required: {
                    message: "Нужно указать время начала следующего этапа",
                    onlyIf: function () {
                        return _this.showClock();
                    }
                }
            });
            this.stageOptions = [
                { id: 0, title: "Черновик (не виден в общем списке)" },
                { id: 1, title: "Ожидание старта" },
                { id: 2, title: "Прием работ" },
                { id: 3, title: "Подготовка к самосуду" },
                { id: 4, title: "Самосуд" },
                { id: 5, title: "Подготовка к работе жюри" },
                { id: 6, title: "Работа жюри" },
                { id: 7, title: "Конкурс окончен" }
            ];
            this.customApplyFormText = ko.observable();
            this.description = ko.observable();
            this.results = ko.observable();
            this.selfJuryGroupCount = ko.observable();
            this.id = options.id;
            this.sponsor(options.sponsor);
            this.contestType(options.contestType);
            this.stageId(options.stageId);
            this.allAwards = options.allAwards;
            this.awardId(options.awardId);
            setTimeout(function () {
                _this.initValidation();
                _this.stageId.subscribe(function (stageId) {
                    switch (stageId) {
                        case 1:
                            _this.subTitle("До начала конкурса осталось");
                            break;
                        case 2:
                            _this.subTitle("Идет прием работ. Осталось:");
                            break;
                        case 3:
                        case 5:
                            _this.subTitle("Идет подготовка к следующему этапу...\r\nЭто может занять некоторое время.\r\nСпасибо за ожидание.");
                            _this.showClock(false);
                            break;
                        case 4:
                            _this.subTitle("Начался этап «Самосуд».\r\nДо завершения осталось:");
                            break;
                        case 6:
                            _this.subTitle("Работает жюри.\r\nДо завершения конкурса осталось:");
                            break;
                        case 7:
                            _this.subTitle("Конкурс завершен.\r\nВ конкурсе приняло участие N рассказов");
                            _this.showClock(false);
                            break;
                    }
                });
            }, 0);
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
            $('#editOgImageFileInput').on("change", function (e) {
                _this.errorMessages([]);
                var $input = $(e.target), files = e.target.files;
                if (files && files.length) {
                    var file = files[0];
                    if (file.type == 'image/tiff') {
                        alert("Данное расширение файла не поддерживается");
                        $input.val("");
                    }
                    var blobUrl = URL.createObjectURL(file);
                    imageUtils_1.default.getImageSize(blobUrl).done(function (imageSize) {
                        if (imageSize.width != 1140 || imageSize.height != 550) {
                            alert("Размер изображения должен быть 1140х550 пикселей");
                            $input.val("");
                        }
                    });
                }
            });
        }
        ViewModel.prototype.confirmMassAward = function () {
            var _this = this;
            var award = this.selectedAward();
            if (!award) {
                alert("Пожалуйста, выберите награду.");
                return;
            }
            this.showModal({
                title: "Массовое вручение наград",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0432\u0441\u0435\u043C \u0432\u044B\u0434\u0430\u0442\u044C \u043D\u0430\u0433\u0440\u0430\u0434\u0443 \"" + award.title + "\" ?",
                type: modalDialog_1.ModalType.Confirm,
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("contest/massAward", {
                        id: _this.id,
                        awardId: award.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success("Награда была успешно выдана");
                        }
                    });
                }
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.isSuccessful && result.data && result.data.redirectUrl) {
                this.forceRedirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/imageUtils":56,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216,"toastr":199}],108:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "numeral", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.workId = ko.observable();
            this.value = ko.observable();
            this.price = ko.pureComputed(function () {
                var value = _this.value();
                if (!value)
                    return "";
                var workId = parseInt(_this.workId());
                var selectedWork = _.find(_this.works, function (w) { return w.id === workId; });
                return numeral(selectedWork.price).format("0,0.00 $");
            });
            this.priceWithDiscount = ko.pureComputed(function () {
                var value = _this.value();
                if (!value)
                    return "";
                var workId = parseInt(_this.workId());
                var selectedWork = _.find(_this.works, function (w) { return w.id === workId; });
                return numeral(selectedWork.price - selectedWork.price * value / 100).format("0,0.00 $");
            });
            this.startDate = ko.observable();
            this.dayCount = ko.observable();
            this.endDate = ko.pureComputed(function () {
                var startDate = _this.startDate(), dayCount = _this.dayCount();
                return moment(startDate).add(dayCount, "d");
            });
            this.repeatable = ko.observable();
            this.repeatableOptions = [
                { id: 0, title: "Нет" },
                { id: 1, title: "Каждые 2 недели" },
                { id: 2, title: "Каждый месяц" }
            ];
            this.id = options.id;
            this.auId = options.auId;
            this.works = options.works;
            this.workId(options.workId);
            this.repeatable(options.repeatable);
            this.startDate(options.startDate);
            setTimeout(function () {
                _this.initValidation();
            }, 100);
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        ViewModel.prototype.showDeleteModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление скидки",
                message: "Вы точно хотите удалить эту скидку?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("discount/delete", {
                        id: _this.id,
                        auId: _this.auId
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                        else {
                            alert(result.messages[0]);
                            _this.modal.hide();
                        }
                    });
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216,"moment":219,"numeral":220}],109:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "nprogress", "drop", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/dateTimeUtils", "../utils/richContentUtils", "../utils/commentUtils", "../utils/postUtils", "../plugins/stickySidebar"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var nprogress = require("nprogress");
    var Drop = require("drop");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var commentUtils_1 = require("../utils/commentUtils");
    var postUtils_1 = require("../utils/postUtils");
    var stickySidebar_1 = require("../plugins/stickySidebar");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.$feed = $(".feed");
            this.isLoading = ko.observable(false);
            this.moreData = false;
            this.offset = ko.observable();
            this.category = options.category;
            this.pageSize = options.pageSize;
            this.moreData = options.more;
            this.lastItemCreationTime = options.lastItemCreationTime;
            this.offset(this.pageSize);
            var $window = $(window), $document = $(document);
            $window.on("scroll.loadData", function () {
                if (_this.moreData && $window.scrollTop() >= $document.height() - $(window).height() - 200) {
                    _this.loadData();
                }
            });
            // Небольшой костыль для кнопок "Подтвердить и стать соавтором". При загрузке страницы они почему-то недоступны
            setTimeout(function () { _this.processing(false); });
            $(document).ready(function () {
                stickySidebar_1.default.init($("#sticky"), {
                    sidebarTopMargin: 64,
                    navSelector: ".my-profile",
                    contentSelector: ".inner-content"
                });
                _this.initDropComments();
                var $feed = $(".feed");
                richContentUtils_1.default.processHtml($feed);
                commentUtils_1.default.reInitNewComments($feed);
                postUtils_1.default.startViewStatsCollector();
            });
            this.errorMessages.subscribe(function (err) {
                if (err && err.length) {
                    toastr.error(err[0]);
                }
            });
        }
        ViewModel.prototype.loadData = function () {
            var _this = this;
            if (!this.isLoading()) {
                this.isLoading(true);
                nprogress.start();
                ajaxUtils_1.AjaxUtils.getHtml("feed/loadMore", {
                    offset: this.offset(),
                    category: this.category,
                    lastItemCreationTime: this.lastItemCreationTime
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                    }
                    else {
                        _this.moreData = result.data.more;
                        _this.lastItemCreationTime = result.data.creationTime;
                        _this.offset(_this.offset() + _this.pageSize);
                        var $newContent = $(result.data.html);
                        $newContent.appendTo(_this.$feed);
                        $newContent.each(function (index, el) {
                            $(el).addClass("ko-not-initialized");
                        });
                        dateTimeUtils_1.default.displayTime($newContent);
                        richContentUtils_1.default.processHtml($newContent);
                        commentUtils_1.default.reInitNewComments($newContent);
                        _this.initDropComments($newContent);
                        _this.notificationCountReload();
                        setTimeout(function () {
                            $(".feed").find(".ko-not-initialized").each(function (index, el) {
                                ko.applyBindings(_this, el);
                                $(el).removeClass("ko-not-initialized");
                            });
                        });
                    }
                    _this.isLoading(false);
                    nprogress.done();
                });
            }
        };
        /** Показывает уведомления группы */
        ViewModel.prototype.showGroupNotifications = function (event, groupId, creationTime, level) {
            if (level === void 0) { level = 1; }
            var $container = level == 1 ? $(event.target).parent().parent() : $(event.target).parent().parent().parent();
            var $containerMore = $(event.target).parent();
            var $feedDetails = $container.parent().find('.feed-details');
            var $spinner = $container.find('.widget-spinner');
            $containerMore.hide();
            $spinner.show();
            ajaxUtils_1.AjaxUtils.getHtml("feed/showgroupnotifications", {
                groupId: groupId,
                lastNotificationCreationTime: creationTime
            }).done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    $containerMore.show();
                }
                else {
                    $feedDetails.hide();
                    $container.html(result.data.html);
                    dateTimeUtils_1.default.displayTime($container);
                }
            }).fail(function () {
                $containerMore.show();
            }).always(function () {
                $spinner.hide();
            });
            event.preventDefault();
        };
        /** Перезагрузка счетчика непрочитанных уведомлений */
        ViewModel.prototype.notificationCountReload = function () {
            ajaxUtils_1.AjaxUtils.get("notification/check", {})
                .done(function (result) {
                if (!result.isSuccessful) {
                    return;
                }
                var notificationCountEl = $("#userNotificationCount");
                if (result.data.userNotificationCount === 0) {
                    notificationCountEl.hide();
                }
                else {
                    notificationCountEl.show();
                }
                notificationCountEl.html(result.data.userNotificationCount);
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result, formElement) {
            if (result.isSuccessful) {
                if (result.data.refuse) {
                    $(formElement).replaceWith("<span class=\"label label-success\">Вы отказались стать соавтором</span>");
                }
                else {
                    $(formElement).replaceWith("<span class=\"label label-success\">Вы подтвердили соавторство</span>");
                }
            }
        };
        ViewModel.prototype.initDropComments = function ($container) {
            if ($container === void 0) { $container = null; }
            if (!$container) {
                $container = $(".feed");
            }
            $container.find("a[data-show-comment]").each(function (i, el) {
                var commentHref = $(el).attr("data-show-comment"), commentId = commentHref.split("_")[0], elId = commentHref + "_container";
                var dropOptions = {
                    target: el,
                    content: "<div id=" + elId + ">\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F...</div>",
                    openOn: "hover",
                    openDelay: 100,
                    closeDelay: 500,
                    constrainToScrollParent: true,
                    classes: "drop-theme-arrows drop-view-comment",
                    tetherOptions: {
                        attachment: "bottom center",
                        targetAttachment: "top center",
                        constraints: [{ to: ".wrapper", pin: true }],
                        offset: "10px 0"
                    }
                };
                var drop = new Drop(dropOptions);
                drop.once("open", function () {
                    ajaxUtils_1.AjaxUtils.get("comment/get", { id: commentId }).done(function (result) {
                        if (result.isSuccessful) {
                            $("#" + elId).html(result.data.html);
                            dateTimeUtils_1.default.displayTime($("#" + elId));
                            richContentUtils_1.default.processHtml($("#" + elId));
                        }
                        else {
                            $("#" + elId).html("Произошла ошибка.");
                        }
                        drop.position();
                    });
                });
            });
        };
        ViewModel.prototype.dispose = function () {
            $(window).off("scroll.loadData");
        };
        /** Отметить все прочитанными */
        ViewModel.prototype.markAllAsRead = function () {
            this.post("mark-all-as-read");
        };
        /** Меняет настройку показа непрочитанных уведомлений */
        ViewModel.prototype.toggleOnlyUnread = function () {
            this.post("toggle-only-unread");
        };
        /** Отправляет пост запрос */
        ViewModel.prototype.post = function (actionName) {
            var _this = this;
            if (this.processing())
                return;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("feed/" + actionName, {})
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                }
                else {
                    location.href = location.href;
                }
            }).always(function () {
                setTimeout(function () {
                    _this.processing(false);
                }, 0);
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../plugins/stickySidebar":43,"../utils/ajaxUtils":45,"../utils/commentUtils":49,"../utils/dateTimeUtils":52,"../utils/postUtils":64,"../utils/richContentUtils":67,"./base/validatedViewModel":93,"drop":197,"jquery":214,"knockout":191,"nprogress":193,"toastr":199}],110:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.selectedItems = ko.observableArray();
            this.processing = ko.observable(false);
            this.handleCheckboxes();
            $(document).on("pjax:complete", function () { return _this.handleCheckboxes(); });
        }
        ViewModel.prototype.markAsRead = function () {
            var _this = this;
            var ids = this.selectedItems();
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("comment/markAsRead", { ids: ids })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.reloadPage(".panel-body");
            })
                .always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.unsubscribe = function () {
            var _this = this;
            var ids = this.selectedItems();
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("comment/unsubscribeMany", { ids: ids })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.reloadPage(".panel-body");
            })
                .always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.handleCheckboxes = function () {
            var _this = this;
            $(".table th .checkbox input").on("click", function (event) {
                var isChecked = $(".table th .checkbox input").prop("checked");
                $(".table td .checkbox input").each(function (i, el) {
                    $(el).prop("checked", isChecked);
                    $(el).trigger("change");
                });
            });
            $(".table td .checkbox input").on("change", function (e) {
                var id = $(e.target).attr("id");
                if ($(e.target).prop("checked")) {
                    _this.selectedItems.push(id);
                }
                else {
                    _this.selectedItems.remove(id);
                }
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191}],111:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "lodash", "numeral", "./base/validatedViewModel", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var _ = require("lodash");
    var numeral = require("numeral");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.plusOne = ko.observable();
            this.phone = ko.observable().extend({
                required: true,
                validation: {
                    validator: function (val, params) {
                        var russia = /^(\+|)(7|8)( |)\d{3}( |)\d{3}( |)(\d{2}( |)){2}$/;
                        var international = /^\+[1-9]{1}[0-9]{3,14}$/;
                        return russia.test(val) || international.test(val);
                    },
                    message: "Пожалуйста, укажите корректный номер телефона."
                }
            });
            this.tariffs = this.options.tariffs;
            this.tariffId = ko.observable();
            this.selectedTariff = ko.pureComputed(function () {
                var tariffId = _this.tariffId();
                return _.find(_this.tariffs, function (t) {
                    return t.id === tariffId;
                });
            });
            this.comment = ko.observable();
            this.moderatorComment = ko.observable();
            this.numeral = numeral;
            this.state = ko.observable(this.options.state);
            this.stateOptions = [
                { id: "New", title: "Новая" },
                { id: "Approved", title: "Подтверждена, ожидает оплаты" },
                { id: "Paid", title: "Участие оплачено" },
                { id: "FreeAccess", title: "Бесплатный доступ" }
            ];
            this.priceToPay = ko.observable().extend({
                required: {
                    message: "Укажите сумму для оплаты",
                    onlyIf: function () {
                        return _this.state() === 'Approved';
                    }
                },
                number: true,
                min: 1
            });
            this.froalaOptions = {
                heightMin: 75,
                heightMax: 400,
                charCounterMax: 25000,
                placeholderText: "Написать комментарий...",
                pastePlain: true,
                charCounterCount: true,
                imageDefaultDisplay: "block",
                imageEditButtons: ["imageReplace", "imageAlign", "imageDisplay",
                    "imageAlt", "imageSize", "imageRemove"],
                imageDefaultAlign: "left",
                htmlAllowedTags: [
                    "a", "b", "blockquote", "br", "del", "div", "em", "embed", "i",
                    "img", "p", "small", "span", "strike", "strong", "u"
                ],
                toolbarButtons: ["bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage"],
                toolbarButtonsMD: ["bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage"],
                toolbarButtonsSM: ["bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage"],
                toolbarButtonsXS: ["bold", "italic", "underline", "strikeThrough", "|", "quote", "emoticons", "spoiler", "insertLink", "insertImage"]
            };
            setTimeout(function () {
                _this.initValidation();
                _this.tariffId(_this.options.tariffId);
                if (_this.options.state !== 'Approved') {
                    _this.state.subscribe(function () {
                        _this.priceToPay(_this.selectedTariff().price);
                    });
                    _this.selectedTariff.subscribe(function (t) {
                        _this.priceToPay(t.price);
                    });
                }
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            var _this = this;
            if (result.isSuccessful) {
                if (this.options.applicationId === null && result.data.redirectUrl) {
                    this.showModal({
                        title: "Успех",
                        message: "Вы успешно подали заявку! Пожалуйста, ожидайте.",
                        maxWidth: "450px",
                        type: modalDialog_1.ModalType.Success,
                        onHide: function () {
                            if (result.data && result.data.redirectUrl) {
                                _this.forceRedirectToPage(result.data.redirectUrl);
                            }
                        }
                    });
                }
            }
            else {
                this.reloadPage();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../components/modalDialog":20,"./base/validatedViewModel":93,"knockout":191,"lodash":216,"numeral":220}],112:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var Clipboard = require("clipboard");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.clipboard = null;
            if (this.clipboard) {
                this.clipboard.destroy();
            }
            this.clipboard = new Clipboard("#promocode", {
                text: function (el) { return $(el).attr("data-clipboard"); }
            });
            this.clipboard.off("sucess");
            this.clipboard.on("success", function (e) {
                var $el = $(e.trigger);
                $el.attr("data-hint-prev", $el.attr("data-hint"))
                    .attr("data-hint", "Промокод скопирован")
                    .addClass("hint-always");
                setTimeout(function () {
                    $el.attr("data-hint", $el.attr("data-hint-prev")).removeClass("hint-always");
                }, 3000);
            });
            this.clipboard.on("error", function (e) {
                var $el = $(e.trigger);
                var url = location.origin + $el.attr("data-clipboard");
                prompt("Чтобы скопировать промокод, нажмите Ctrl+C и потом Enter.", url);
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"clipboard":202,"jquery":214}],113:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.updateState = function (newState) {
                var grid = $("#grid").data("kendoGrid");
                var rows = grid.select();
                var requestData = {
                    ids: [],
                    state: newState
                };
                rows.each(function (index, row) {
                    var selectedItem = grid.dataItem(row);
                    requestData.ids.push(selectedItem.Id);
                });
                return ajaxUtils_1.AjaxUtils.post("forum/update-application-state", requestData)
                    .done(function (result) {
                    if (result.isSuccessful) {
                        grid.dataSource.read();
                    }
                    else {
                        alert(result.messages[0]);
                    }
                });
            };
            this.id = options.id;
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214}],114:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "numeral", "../../app/components/modalDialog", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var numeral = require("numeral");
    var modalDialog_1 = require("../../app/components/modalDialog");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.numeral = numeral;
            this.selectedOrder = ko.observable();
            this.formatState = function (state) {
                switch (state) {
                    case 1:
                    case "New":
                        return "<i class='icon-clock-o'></i> Ожидает оплаты";
                    case 2:
                    case "Paid":
                        return "<span class='text-success text-bold'><i class='icon-check'></i> Оплачен </span>";
                    case 3:
                    case "Failed":
                        return "<span class='text-danger'><i class='icon-cross'></i> Ошибка </span>";
                    case 4:
                    case "Blocked":
                        return "<span class='text-danger'><i class='icon-cross'></i> Доступ заблокирован </span>";
                    case 11:
                    case "Pending":
                        return "<i class='icon-clock-o'></i> Pending";
                    case "Captured":
                    case 12:
                        return "<span class='text-success text-bold'><i class='icon-clock-o'></i> Captured </span>";
                    case 13:
                    case "Canceled":
                        return "<span class='text-danger'><i class='icon-cross'></i> Отменён </span>";
                    default:
                        return "Неизвестно";
                }
            };
            $("#grid").on("click", ".btn-edit-order", function (e) {
                if (_this.grid === undefined) {
                    _this.grid = $("#grid").data("kendoGrid");
                }
                var dataItem = _this.grid.dataItem($(e.currentTarget).parents("tr")[0]);
                _this.selectedOrder(dataItem);
                _this.showModal({
                    title: "Заказ #" + dataItem.Id,
                    type: modalDialog_1.ModalType.Custom,
                    templateId: "editOrderModal",
                    viewModel: _this,
                    maxWidth: "650px",
                    minWidth: "650px"
                });
            });
        }
        ViewModel.prototype.onSubmitSucess = function () {
            this.modal.hide();
            if (this.grid === undefined) {
                this.grid = $("#grid").data("kendoGrid");
            }
            this.grid.dataSource.read();
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../../app/components/modalDialog":20,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"numeral":220}],115:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.title = ko.observable().extend({
                required: true
            });
            this.description = ko.observable();
            this.handleTariffChanges = function (e) {
                setTimeout(function () {
                    $("#forumTariffs").data("kendoGrid").dataSource.read();
                }, 200);
            };
            this.handleGridError = function (e) {
                if (e.errors) {
                    var message = "Ошибки:\n";
                    $.each(e.errors, function (key, value) {
                        if ('errors' in value) {
                            $.each(value.errors, function () {
                                message += this + "<br>";
                            });
                        }
                    });
                    toastr.error(message);
                }
            };
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.isSuccessful && result.data && result.data.redirectUrl) {
                this.forceRedirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"./base/validatedViewModel":93,"jquery":214,"knockout":191}],116:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.processing = ko.observable(true);
            this.offerAccept = ko.observable(false);
            this.createOrder = function () {
                ajaxUtils_1.AjaxUtils.get("forum/create-ticket-order", { applicationId: _this.options.applicationId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        toastr.error(result.messages[0]);
                        return;
                    }
                    _this.forceRedirectToPage(result.data.paymentUrl);
                }).always(function () {
                    _this.processing(false);
                });
            };
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"knockout":191}],117:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "../utils/localStorageUtils", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.workPreferencesPreset = ko.observable("Default");
            this.workPreferencesModalState = ko.observable("selectPreset");
            this.ignoredGenreIds = ko.observableArray();
            this.hideDislike = ko.observable(false);
            this.hideFinished = ko.observable(false);
            this.initWorkPreferencesPreset = function () {
                _this.ignoredGenreIds.subscribe(function (values) {
                    _this.ignoredGenreIds.subscribe(function (values) {
                        _.forOwn(_this.genres, function (subGenres, genre) {
                            if (values.indexOf(genre) !== -1 && _.intersection(values, subGenres).length > 0) {
                                _this.ignoredGenreIds.removeAll(subGenres);
                            }
                        });
                    });
                });
            };
            this.genres = {
                "1": ["76"],
                "2": ["38", "71", "77", "64", "39", "41", "78", "74", "40", "44", "73", "43", "42", "79", "80"],
                "3": ["28", "29", "30", "31", "34", "33", "36", "32", "63", "35", "37", "81"],
                "4": ["50", "52", "51"],
                "6": ["46", "45", "67"],
                "7": ["53", "57", "54", "55", "56", "68"],
                "8": ["70"],
                "19": ["61", "58", "14", "59", "60", "82"],
                "21": ["66", "48", "47", "72"]
            };
            this.selectWorkPreferencesPreset = function () {
                var preset = _this.workPreferencesPreset();
                if (preset === "Custom") {
                    _this.workPreferencesModalState("editCustomPreset");
                    setTimeout(function () {
                        $(".genre-item-btn").on("click", function (e) {
                            var $btn = $(e.currentTarget);
                            if ($btn.hasClass("active")) {
                                $btn.removeClass("active");
                                $btn.siblings(".collapse").removeClass("in");
                            }
                            else {
                                $btn.addClass("active");
                                $btn.siblings(".collapse").addClass("in");
                            }
                        });
                    }, 200);
                }
            };
            this.backToSelectPreset = function () {
                _this.workPreferencesModalState("selectPreset");
            };
            this.saveWorkPreferences = function () {
                var preset = _this.workPreferencesPreset();
                if (preset === "Custom" && _this.ignoredGenreIds().length === 0) {
                    _this.errorMessages.push("Выберите хотя бы один жанр или вернитесь назад.");
                    return;
                }
                _this.processing(true);
                ajaxUtils_1.AjaxUtils.post("account/workPreferences", {
                    preset: _this.workPreferencesPreset(),
                    ignoredGenreIds: _this.ignoredGenreIds(),
                    hideDislike: _this.hideDislike() !== false,
                    hideFinished: _this.hideFinished() !== false
                })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        _this.errorMessages(result.messages);
                        if (result.data && result.data.stackTrace !== undefined) {
                            console.error(result.data.stackTrace);
                        }
                        return;
                    }
                    _this.workPreferencesModalState("saved");
                    setTimeout(function () {
                        _this.fullReloadPage();
                    }, 1500);
                })
                    .always(function () {
                    _this.processing(false);
                });
            };
            this.clearIgnoredGenres = function () {
                _this.ignoredGenreIds([]);
            };
            try {
                var recentlyViewedWorkIds = localStorageUtils_1.default.get(localStorageUtils_1.default.RecentlyViewedKey);
                var $recentlyViewedPanel = $("#recentlyViewedPanel");
                if (!recentlyViewedWorkIds || recentlyViewedWorkIds.length === 0) {
                    $recentlyViewedPanel.hide();
                }
                ajaxUtils_1.AjaxUtils.get("work/getByIds", { workIds: recentlyViewedWorkIds, format: options.format })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        $recentlyViewedPanel.hide();
                        return;
                    }
                    $("#recentlyViewed").addClass("slick-container");
                    $("#recentlyViewed").html(result.data.html);
                    _this.initWorksCarousel("#recentlyViewed");
                }).fail(function () {
                    $recentlyViewedPanel.hide();
                });
            }
            catch (ex) {
                console.error(ex);
            }
            this.initWorksCarousel("#hotWorks");
            this.initWorksCarousel("#recentUpdWorks");
            this.initWorksCarousel("#mostPopularWorks");
            this.initWorksCarousel("#bestsellerWorks");
            this.initWorksCarousel("#addedToLibraryWorks");
            this.initWorksCarousel("#recentLikedWorks");
            this.initWorksCarousel("#recentPubWorks");
            $("#atRecs").slick({
                touchMove: false,
                fade: true
            });
            setTimeout(function () {
                _this.initWorkPreferencesPreset();
            }, 200);
        }
        ViewModel.prototype.initWorksCarousel = function (id) {
            var $carousel = $(id);
            $carousel.slick({
                slidesToShow: 6,
                slidesToScroll: 6,
                adaptiveHeight: true,
                touchMove: false,
                responsive: [
                    {
                        breakpoint: 1200,
                        settings: {
                            slidesToShow: 5,
                            slidesToScroll: 5
                        }
                    },
                    {
                        breakpoint: 992,
                        settings: {
                            slidesToShow: 3,
                            slidesToScroll: 3
                        }
                    }, {
                        breakpoint: 768,
                        settings: {
                            slidesToShow: 4,
                            slidesToScroll: 4
                        }
                    }
                ]
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/localStorageUtils":59,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216}],118:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/localStorageUtils", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(true);
            this.widgetHtml = ko.observable();
            var recentlyViewedWorkIds = localStorageUtils_1.default.get(localStorageUtils_1.default.RecentlyViewedKey);
            var $recentlyViewedPanel = $("#recentlyViewedPanel");
            var showCarousel = recentlyViewedWorkIds && recentlyViewedWorkIds.length > 0;
            ajaxUtils_1.AjaxUtils.get("work/getByIds", { workIds: recentlyViewedWorkIds })
                .done(function (result) {
                if (!result.isSuccessful) {
                    $recentlyViewedPanel.hide();
                    return;
                }
                if (showCarousel) {
                    $("#recentlyViewed").addClass("slick-container");
                }
                $("#recentlyViewed").html(result.data.html);
                if (showCarousel) {
                    _this.initWorksCarousel("#recentlyViewed");
                }
            }).fail(function () {
                $recentlyViewedPanel.hide();
            });
        }
        ViewModel.prototype.initWorksCarousel = function (id) {
            var $carousel = $(id);
            $carousel.slick({
                slidesToShow: 6,
                slidesToScroll: 6,
                adaptiveHeight: true,
                touchMove: false,
                responsive: [
                    {
                        breakpoint: 1200,
                        settings: {
                            slidesToShow: 5,
                            slidesToScroll: 5
                        }
                    },
                    {
                        breakpoint: 992,
                        settings: {
                            slidesToShow: 3,
                            slidesToScroll: 3
                        }
                    }, {
                        breakpoint: 768,
                        settings: {
                            slidesToShow: 4,
                            slidesToScroll: 4
                        }
                    }
                ]
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/localStorageUtils":59,"./base/baseViewModel":92,"jquery":214,"knockout":191}],119:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "numeral", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.groupBy = ko.observable();
            this.itemTitle = ko.pureComputed(function () {
                var groupBy = _this.groupBy();
                if (groupBy === "work") {
                    return "Произведения";
                }
                else if (groupBy === "series") {
                    return "Циклы";
                }
                else if (groupBy === "format") {
                    return "Формат";
                }
                return "";
            });
            this.items = ko.pureComputed(function () {
                var groupBy = _this.groupBy();
                var items = [];
                if (groupBy === "work") {
                    items = _this.works.slice();
                    items.unshift({ id: "null", title: "Все" });
                }
                else if (groupBy === "series") {
                    items = _this.series.slice();
                    items.unshift({ id: "null", title: "Все" }, { id: "0", title: "Без цикла" });
                }
                else if (groupBy === "format") {
                    items = _this.workFormat.slice();
                    items.unshift({ id: "null", title: "Все" });
                }
                return items;
            });
            this.itemId = ko.observable();
            this.numeral = numeral;
            this.dateRangePickerOptions = {
                ranges: {
                    'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                    'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")],
                    'За прошлый месяц': [moment().startOf("day").add(-30, "days").add(-1, "months"), moment().startOf("day").add(-31, "days")],
                    'За 3 месяца': [moment().startOf("day").add(-30, "days").add(-2, "months"), moment().endOf("day")],
                    'За год': [moment().startOf("day").add(-12, "months"), moment().endOf("day")]
                }
            };
            this.startDate = ko.observable();
            this.endDate = ko.observable();
            this.isLoading = ko.observable(true);
            this.workCountByPeriod = ko.observable(0);
            this.rewardCountByPeriod = ko.observable(0);
            this.incomeByPeriod = ko.observable(0);
            this.totalWorkCount = ko.observable(0);
            this.totalRewardCount = ko.observable(0);
            this.totalIncomeByWork = ko.observable(0);
            this.totalIncome = ko.observable(0);
            this.currentBalance = ko.observable(0);
            this.getFilterData = function () {
                return _this.filterData();
            };
            this.auId = options.auId;
            this.works = options.works;
            this.series = options.series;
            this.workFormat = options.workFormat;
            this.startDate(options.startDate ? moment(options.startDate) : moment().startOf("day").add(-6, "days"));
            this.endDate(options.endDate ? moment(options.endDate) : moment().endOf("day"));
            this.filterData = ko.computed(function () {
                var filterData = {
                    groupBy: _this.groupBy(),
                    startDate: _this.startDate().toISOString(),
                    endDate: _this.endDate().toISOString(),
                    itemId: _this.itemId(),
                    auId: _this.auId
                };
                return filterData;
            }).extend({
                rateLimit: {
                    timeout: 300,
                    method: "notifyWhenChangesStop"
                }
            });
            var isInitialized = false;
            setTimeout(function () {
                ko.computed(function () {
                    var data = _this.filterData();
                    if (!isInitialized)
                        return;
                    _this.isLoading(true);
                    _this.loadDynamicChart();
                    var grid = $("#grid").data("kendoGrid");
                    if (grid) {
                        grid.dataSource.read(data);
                    }
                    try {
                        if (!data.itemId || data.itemId === "null") {
                            delete data.itemId;
                        }
                        if (!data.auId || data.auId === "null") {
                            delete data.auId;
                        }
                        history.replaceState(null, null, "dashboard?" + $.param(data));
                    }
                    catch (e) {
                    }
                });
            });
            this.filterData.subscribe(function () {
                isInitialized = true;
            });
        }
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("merchant/workOrdersReport", this.filterData())
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                var reportData = result.data;
                var daysInPerios = Math.floor((_this.endDate() - _this.startDate()) / (1000 * 60 * 60 * 24));
                var minPeriod = "DD";
                var categoryBalloonDateFormat = "MMMM DD, YYYY";
                if (daysInPerios > 40) {
                    minPeriod = "MM";
                    categoryBalloonDateFormat = "MMMM, YYYY";
                }
                _this.dynamicChart = AmCharts.makeChart("chartdiv", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    synchronizeGrid: true,
                    thousandsSeparator: " ",
                    valueAxes: [
                        {
                            id: "v1",
                            position: "left",
                            title: "Доход, ₽",
                            stackType: "regular",
                        },
                        {
                            id: "v2",
                            axisAlpha: 0,
                            gridAlpha: 0,
                            position: "right",
                            integersOnly: true,
                            title: "Количество"
                        }
                    ],
                    graphs: [
                        {
                            balloonFunction: function (item) {
                                var x = item.dataContext;
                                return "<table class='text-left'>" +
                                    ("<tr><td class='text-right'>\u041A\u043D\u0438\u0433\u0438:</td><td>&nbsp;<b>" + numeral(x.workIncome).format("0,0.[00]") + "</b> \u20BD (" + numeral(x.workCount).format("0,0") + " \u0448\u0442.)</td></tr>") +
                                    ("<tr><td class='text-right'>\u041D\u0430\u0433\u0440\u0430\u0434\u044B:</td><td>&nbsp;<b>" + numeral(x.rewardIncome).format("0, 0.[00]") + "</b> \u20BD (" + numeral(x.rewardCount).format("0,0") + " \u0448\u0442.)</td></tr>") +
                                    ("<tr><td class='text-right'>\u0412\u0441\u0435\u0433\u043E:</td><td>&nbsp;<b>" + numeral(x.rewardIncome + x.workIncome).format("0, 0.[00]") + "</b> \u20BD</td></tr>") +
                                    "</table>";
                            },
                            fillAlphas: 0.7,
                            useLineColorForBulletBorder: true,
                            hideBulletsCount: 30,
                            connect: true,
                            legendValueText: "[[value]] ₽",
                            title: "За книги",
                            type: "column",
                            valueField: "workIncome",
                            valueAxis: "v1",
                            showBalloon: true
                        },
                        {
                            balloonText: "За награды: [[value]] ₽",
                            fillAlphas: 0.7,
                            useLineColorForBulletBorder: true,
                            hideBulletsCount: 30,
                            connect: true,
                            legendValueText: "[[value]] ₽",
                            title: "За награды",
                            type: "column",
                            valueField: "rewardIncome",
                            valueAxis: "v1",
                            lineColor: "#84b761",
                            showBalloon: false
                        }, {
                            balloonText: "Купили книг: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]]",
                            title: "Купили книг",
                            fillAlphas: 0,
                            valueField: "workCount",
                            valueAxis: "v2",
                            lineColor: "#fdd400",
                            showBalloon: false
                        }, {
                            balloonText: "Купили наград: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]]",
                            title: "Подарили наград",
                            fillAlphas: 0,
                            valueField: "rewardCount",
                            valueAxis: "v2",
                            lineColor: "#FF6600",
                            showBalloon: false
                        }
                    ],
                    chartCursor: {
                        categoryBalloonDateFormat: categoryBalloonDateFormat,
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY",
                    categoryField: "processedTime",
                    categoryAxis: {
                        parseDates: true,
                        dashLength: 1,
                        minPeriod: minPeriod
                    },
                    legend: {
                        equalWidths: true,
                        useGraphSettings: true,
                        align: "center"
                    },
                    dataProvider: reportData.dynamicChartData,
                    pathToImages: window["app"].rootUrl + "dist/vendor/amcharts/images/",
                    "export": {
                        enabled: false
                    }
                });
                // Костыль против глюка SVG в Хроме
                function endsWith(str, suffix) {
                    return str.indexOf(suffix, str.length - suffix.length) !== -1;
                }
                var badPart = "M0,0 L0,0";
                setTimeout(function () {
                    $("svg path").each(function (i, el) {
                        var dAttr = $(el).attr("d");
                        if (endsWith(dAttr, badPart)) {
                            $(el).attr("d", dAttr.substring(0, dAttr.length - badPart.length));
                        }
                    });
                }, 50);
                _this.workCountByPeriod(reportData.workCountByPeriod);
                _this.rewardCountByPeriod(reportData.rewardCountByPeriod);
                _this.incomeByPeriod(reportData.incomeByPeriod);
                _this.totalWorkCount(reportData.totalWorkCount);
                _this.totalRewardCount(reportData.totalRewardCount);
                _this.totalIncomeByWork(reportData.totalIncomeByWork);
                _this.totalIncome(reportData.totalIncome);
                _this.currentBalance(reportData.currentBalance);
                _this.isLoading(false);
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191,"moment":219,"numeral":220}],120:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "../utils/dateTimeUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.initGrid = function (e) {
                var grid = $("#grid").data("kendoGrid");
                var items = e.sender.items();
                $(items).each(function (i, el) {
                    var $el = $(el);
                    var dataItem = grid.dataItem(el);
                    if (dataItem.IsActive) {
                        $el.addClass("active-discount");
                    }
                    else if (dataItem.IsPast) {
                        $el.addClass("past-discount");
                    }
                });
                //items.
                //items.each(function (index) {
                //    var dataItem = grid.dataItem(this);
                //    if (dataItem.age > 32) {
                //        this.className += " customClass1";
                //    }
                //    else {
                //        this.className += " customClass2";
                //    }
                //})
                dateTimeUtils_1.default.displayTime();
            };
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/validatedViewModel":93,"jquery":214}],121:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "numeral", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var numeral = require("numeral");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.numeral = numeral;
            this.isLoading = ko.observable(true);
            this.auId = options.auId;
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"knockout":191,"numeral":220}],122:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "./base/validatedViewModel", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.rewards = ko.observable();
            this.sales = ko.observable();
            this.subscription = ko.observable();
            this.comment = ko.observable();
        }
        ViewModel.prototype.openModal = function () {
            this.showModal({
                title: "Получение коммерческого статуса",
                type: modalDialog_1.ModalType.Custom,
                templateId: "sendRequestModal",
                minWidth: "400px",
                maxWidth: "400px",
                viewModel: this
            });
        };
        ViewModel.prototype.submit = function () {
            var _this = this;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            ;
            if (this.processing())
                return;
            this.processing(true);
            this.errorMessages([]);
            var data = {
                rewards: this.rewards(),
                sales: this.sales(),
                subscription: this.subscription(),
                comment: this.comment()
            };
            ajaxUtils_1.AjaxUtils.post("merchant/sendRequest", data)
                .done(function (result) {
                if (result.isSuccessful) {
                    _this.showModal({
                        title: "Заявка успешно отправлена",
                        type: modalDialog_1.ModalType.Success,
                        message: "Спасибо! Мы свяжемся с вами в самое ближайшее время.",
                        maxWidth: "435px"
                    });
                    $("#submitFormBtn").hide();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191}],123:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "moment", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var moment = require("moment");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.name = ko.observable().extend({
                required: true,
                maxLength: 50
            });
            this.surname = ko.observable().extend({
                required: true,
                maxLength: 50
            });
            this.patronymic = ko.observable().extend({ maxLength: 50 });
            this.passportType = ko.observable();
            this.passportTypeOptions = ko.observable();
            /** Для граждан РФ */
            this.russianPassportTypeOptions = [
                { id: 1, title: "Физическое лицо" },
                { id: 2, title: "Индивидуальный предприниматель" },
                { id: 3, title: "Самозанятый" }
            ];
            /** Для иностранцев */
            this.foreignPassportTypeOptions = [
                { id: 1, title: "Иностранный гражданин (физическое лицо)" },
                { id: 2, title: "Индивидуальный предприниматель РФ" },
                { id: 3, title: "Самозанятый РФ" }
            ];
            this.sex = ko.observable().extend({
                validation: {
                    validator: function (val) {
                        return val !== -1;
                    },
                    message: "Нужно указать пол"
                }
            });
            this.sexOptions = [{ id: -1, title: "не выбран" }, { id: 1, title: "женский" }, { id: 2, title: "мужской" }];
            this.citizenship = ko.observable().extend({
                required: true
            });
            this.bankCountry = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return true;
                    }
                }
            });
            this.passportBirthDate = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 1 || _this.passportType() === 3;
                    }
                },
                validation: {
                    validator: function (val) {
                        if (_this.passportType() === 2) {
                            return true;
                        }
                        var years = moment().diff(val, 'years');
                        return years >= 18;
                    },
                    message: "Допускаются только совершеннолетние"
                }
            });
            this.passportSeries = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return (_this.passportType() === 1 || _this.passportType() === 3) && _this.isRussia();
                    }
                },
                maxLength: 4,
                minLength: 4
            });
            this.passportNumber = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return (_this.passportType() === 1 || _this.passportType() === 3) && _this.isRussia();
                    }
                },
                maxLength: 6,
                minLength: 6
            });
            this.passportIssuedDate = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return (_this.passportType() === 1 || _this.passportType() === 3) && _this.isRussia();
                    }
                }
            });
            this.passportByWhomIssued = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return (_this.passportType() === 1 || _this.passportType() === 3) && _this.isRussia();
                    }
                }
            });
            this.passportDetails = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return (_this.passportType() === 1 || _this.passportType() === 3) && !_this.isRussia();
                    }
                }
            });
            this.registrationAddress = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 1;
                    }
                }
            });
            this.INN = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 2 || _this.passportType() === 3;
                    }
                },
                minLength: 12,
                maxLength: 12
            });
            this.OGRNIP = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 2;
                    }
                },
                minLength: 15,
                maxLength: 15
            });
            this.OGRNIPIssueDate = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 2;
                    }
                }
            });
            this.OGRNIPIssuedBy = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 2;
                    }
                }
            });
            this.mailingAddress = ko.observable().extend({ required: true });
            this.BIK = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.strictBankRequisites() && !_this.showYandexMoneyOnly();
                    }
                },
                minLength: 9,
                maxLength: 9
            });
            this.accNumber = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.strictBankRequisites() && !_this.showYandexMoneyOnly();
                    }
                },
                minLength: 20,
                maxLength: 20
            });
            this.bankRequisites = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.passportType() === 1 && !_this.yandexMoneyAccountId() && !_this.isRussianBank();
                    }
                }
            });
            this.strictBankRequisites = ko.observable();
            this.yandexMoneyAccountId = ko.observable().extend({
                number: true,
                required: {
                    onlyIf: function () {
                        return _this.showYandexMoneyOnly();
                    }
                }
            });
            this.offerAgree = ko.observable().extend({ required: true });
            this.isRussia = ko.pureComputed(function () {
                var country = _this.countries.find(function (p) { return p.id == _this.citizenship(); });
                return country && country.isRussia;
            });
            this.isRussianBank = ko.pureComputed(function () {
                var country = _this.countries.find(function (p) { return p.id == _this.bankCountry(); });
                return country && country.isRussia;
            });
            this.showYandexMoneyOnly = ko.pureComputed(function () {
                return (_this.passportType() === 1 || _this.passportType() === 3) && _this.isRussianBank() && _this.yandexMoneyOnly();
            });
            this.FIOPayee = ko.observable();
            /** ИП или самозанятый */
            this.isSelfOccupiedOrSoleProprietor = ko.observable(false);
            this.yandexMoneyOnly = ko.observable();
            this.allowEdit = options.allowEdit;
            if (this.allowEdit && (options.contractStatus === 2 || options.contractStatus === 3 || options.contractStatus === 4 || options.contractStatus === 5)) {
                setTimeout(function () {
                    _this.initValidation();
                }, 0);
            }
            this.passportType.subscribe(function (value) {
                if (value == 2 || value == 3) {
                    var russiaId = _this.countries.find(function (p) { return p.isRussia; }).id;
                    _this.bankCountry(russiaId);
                    _this.isSelfOccupiedOrSoleProprietor(true);
                }
                else {
                    _this.isSelfOccupiedOrSoleProprietor(false);
                }
            });
            this.citizenship.subscribe(function (value) {
                var isRussia = _this.checkIsRussia(value);
                if (isRussia) {
                    _this.passportTypeOptions(_this.russianPassportTypeOptions);
                }
                else {
                    _this.passportTypeOptions(_this.foreignPassportTypeOptions);
                }
            });
            this.passportTypeOptions(this.foreignPassportTypeOptions);
            this.citizenship(options.citizenship);
            this.sex(options.sex);
            this.contractStatus = options.contractStatus;
            this.bankRequisites(options.bankRequisites);
            this.BIK(options.bik);
            this.accNumber(options.accNumber);
            this.countries = options.countries;
            if (options.passportBirthDate) {
                this.passportBirthDate(moment(options.passportBirthDate).toDate());
            }
            this.passportSeries(options.passportSeries);
            this.passportNumber(options.passportNumber);
            this.passportByWhomIssued(options.passportByWhomIssued);
            if (options.passportIssuedDate) {
                this.passportIssuedDate(moment(options.passportIssuedDate).toDate());
            }
            if (options.ogrnipIssueDate) {
                this.OGRNIPIssueDate(moment(options.ogrnipIssueDate).toDate());
            }
            this.strictBankRequisites(false);
            this.bankCountry(options.bankCountry);
            this.bankCountry.subscribe(function (value) {
                var country = _this.countries.find(function (p) { return p.id == value; });
                _this.strictBankRequisites(country && country.isRussia);
            });
            this.FIOPayee(options.FIOPayee);
            this.yandexMoneyOnly(options.yandexMoneyOnly);
            this.errorMessages.subscribe(function (messages) {
                messages.forEach(function (value) {
                    alert(value);
                });
            });
            setTimeout(function () {
                _this.sex.isModified(false);
                if (options.contractStatus === 3 || options.contractStatus === 4 || options.contractStatus === 5) {
                    _this.initValidation();
                }
                _this.passportType(options.passportType);
            }, 0);
        }
        ViewModel.prototype.checkIsRussia = function (value) {
            var country = this.countries.find(function (p) { return p.id == value; });
            return country && country.isRussia;
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data && result.data.redirectUrl) {
                this.redirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"knockout":191,"moment":219}],124:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            var endpoint = window["app"].rootUrl + "file/uploadContractScanCopy";
            $(document).ready(function () {
                var uploader = new qq.FineUploader({
                    //debug: true,
                    multiple: false,
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: endpoint,
                        customHeaders: ajaxUtils_1.AjaxUtils.getHeaders()
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — {sizeLimit}.",
                        typeError: "{file} имеет недопустимый формат. Пожалуйста, выберите файл с расширением .jpg, .jpeg, .png, .pdf."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", 'pdf', "webp"],
                        sizeLimit: 5 * 1024 * 1024
                    },
                    callbacks: {
                        onSubmit: function () {
                            return !_this.isLoading();
                        },
                        onSubmitted: function () {
                            _this.isLoading(true);
                        },
                        onCancel: function () {
                            _this.isLoading(false);
                        },
                        onError: function () {
                            _this.isLoading(false);
                        },
                        onComplete: function (id, name, response) {
                            _this.isLoading(false);
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            toastr.success("Изображение успешно загружено и отправлено на проверку.");
                            _this.reloadPage();
                        }
                    }
                });
            });
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"toastr":199}],125:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.inn = ko.observable();
            this.selfOccupiedSent = ko.observable(false);
            this.selfOccupiedSent(options.selfOccupiedSent);
            $(document).ready(function () {
                _this.createUploader();
            });
        }
        ViewModel.prototype.createUploader = function () {
            var _this = this;
            var uploaderSelfOccupiedElement = document.getElementById("fine-uploader-self-occupied");
            if (uploaderSelfOccupiedElement) {
                var endpointSelfOccupied = window["app"].rootUrl + "file/UploadSelfOccupiedScanCopy";
                var uploaderSelfOccupied = new qq.FineUploader({
                    multiple: false,
                    element: uploaderSelfOccupiedElement,
                    request: {
                        endpoint: endpointSelfOccupied,
                        customHeaders: ajaxUtils_1.AjaxUtils.getHeaders()
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — 5MB.",
                        typeError: "{file} имеет недопустимый формат. Пожалуйста, выберите файл с расширением .jpg, .jpeg, .png, .pdf."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", "pdf", "webp"],
                        sizeLimit: 5 * 1024 * 1024
                    },
                    callbacks: {
                        onSubmit: function () {
                            return !_this.isLoading();
                        },
                        onSubmitted: function () {
                            _this.isLoading(true);
                        },
                        onCancel: function () {
                            _this.isLoading(false);
                        },
                        onError: function () {
                            _this.isLoading(false);
                        },
                        onComplete: function (id, name, response) {
                            _this.isLoading(false);
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            toastr.success("Изображение успешно загружено и отправлено на проверку.");
                            _this.reloadPage();
                        }
                    }
                });
            }
            var uploaderAudioElement = document.getElementById("fine-uploader-audio");
            if (uploaderAudioElement) {
                var endpointAudio = window["app"].rootUrl + "file/uploadAudioContract";
                var uploaderAudio = new qq.FineUploader({
                    multiple: false,
                    element: uploaderAudioElement,
                    request: {
                        endpoint: endpointAudio,
                        customHeaders: ajaxUtils_1.AjaxUtils.getHeaders()
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — 5MB.",
                        typeError: "{file} имеет недопустимый формат. Пожалуйста, выберите файл с расширением .jpg, .jpeg, .png, .pdf."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", "pdf", "webp"],
                        sizeLimit: 5 * 1024 * 1024
                    },
                    callbacks: {
                        onSubmit: function () {
                            return !_this.isLoading();
                        },
                        onSubmitted: function () {
                            _this.isLoading(true);
                        },
                        onCancel: function () {
                            _this.isLoading(false);
                        },
                        onError: function () {
                            _this.isLoading(false);
                        },
                        onComplete: function (id, name, response) {
                            _this.isLoading(false);
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            toastr.success("Изображение успешно загружено и отправлено на проверку.");
                            _this.reloadPage();
                        }
                    }
                });
            }
        };
        ViewModel.prototype.enableRewards = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.post("merchant/enableRewards", {})
                .done(function (result) {
                if (result.isSuccessful) {
                    _this.showModal({
                        title: "Награды включены",
                        type: modalDialog_1.ModalType.Success,
                        message: "Отлично! Теперь читатели смогут награждать ваши книги.",
                        maxWidth: "435px"
                    });
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.applyForAudiobooks = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.post("merchant/applyForAudiobooks", {})
                .done(function (result) {
                if (result.isSuccessful) {
                    _this.showModal({
                        title: "Заявка отправлена",
                        type: modalDialog_1.ModalType.Success,
                        message: "Ваша заявка отправлена на рассмотрение! Ожидайте ответа.",
                        maxWidth: "435px"
                    });
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.showSelfOccupiedModal = function () {
            this.showModal({
                title: "Заявка на получение переводов как самозанятому",
                type: modalDialog_1.ModalType.Custom,
                templateId: "selfOccupiedModal",
                viewModel: this,
                maxWidth: "650px",
                minWidth: "650px"
            });
        };
        ViewModel.prototype.submitSelfOccupied = function () {
            var _this = this;
            if (!this.inn() || this.inn().length != 12) {
                alert("В ИНН должно быть указано 12 цифр");
                return;
            }
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("merchant/sendSelfOccupied", { inn: this.inn() })
                .done(function (result) {
                if (result.isSuccessful) {
                    location.href = location.href;
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.hideSelfOccupied = function () {
            this.modal.hide();
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"toastr":199}],126:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = this.options.query;
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
            });
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (_this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                return false;
            });
        }
        ViewModel.prototype.clearSearchQuery = function () {
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                $(".search-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"jquery":214,"knockout":191}],127:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "nprogress", "crosstab", "../utils/ajaxUtils", "./base/baseViewModel", "../utils/richContentUtils", "../utils/stringUtils", "../utils/webSocketUtils", "../components/modalDialog", "../utils/imageZoomUtils", "nanoScroller"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var nprogress = require("nprogress");
    var crosstab = require("crosstab");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var webSocketUtils_1 = require("../utils/webSocketUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    require("nanoScroller");
    var director = require("director");
    var imagesLoaded = require("imagesloaded");
    var PrivacyPrivateMessage;
    (function (PrivacyPrivateMessage) {
        PrivacyPrivateMessage[PrivacyPrivateMessage["None"] = 0] = "None";
        PrivacyPrivateMessage[PrivacyPrivateMessage["All"] = 1] = "All";
        PrivacyPrivateMessage[PrivacyPrivateMessage["OnlyFriends"] = 2] = "OnlyFriends";
    })(PrivacyPrivateMessage || (PrivacyPrivateMessage = {}));
    var BaseChat = (function () {
        function BaseChat(data, viewModel) {
            var _this = this;
            this.lastActivity = ko.observable().extend({ notify: "always" });
            this.lastMessageId = ko.observable();
            this.lastMessageText = ko.observable();
            this.lastMessageUserId = ko.observable();
            this.lastMessageSentTime = ko.observable();
            this.unreadCount = ko.observable();
            this.sent = ko.pureComputed(function () {
                var currentUserId = _this.viewModel.currentUserId;
                return _this.lastMessageUserId() === currentUserId;
            });
            this.isActive = ko.pureComputed(function () {
                var currentChat = _this.viewModel.currentChat();
                if (currentChat) {
                    return _this.id === currentChat.id;
                }
                return false;
            });
            this.id = data.id;
            this.title = data.title;
            this.isGroup = data.isGroup;
            this.avatarUrl = data.avatarUrl;
            this.lastActivity(moment(data.lastActivity));
            this.lastMessageId(data.lastMessageId);
            this.lastMessageText(data.lastMessageText);
            this.lastMessageUserId(data.lastMessageUserId);
            this.lastMessageSentTime(data.lastMessageSentTime);
            this.unreadCount(data.unreadCount);
            this.viewModel = viewModel;
        }
        return BaseChat;
    }());
    var PrivateChat = (function (_super) {
        __extends(PrivateChat, _super);
        function PrivateChat(data, viewModel) {
            var _this = this;
            _super.call(this, data, viewModel);
            this.unavailableMessage = ko.observable();
            this.isCurrentUserUnavailable = false;
            this.isInvisibleSubscriber = false;
            this.ignored = ko.observable();
            this.online = ko.pureComputed(function () {
                var lastActivity = _this.lastActivity();
                return moment.utc().add(-2, "minutes").isBefore(lastActivity);
            });
            this.allowSendPM = ko.pureComputed(function () {
                return !_this.ignoredByUser
                    && !_this.ignored()
                    && (_this.privacySendPM === PrivacyPrivateMessage.All || (_this.privacySendPM === PrivacyPrivateMessage.OnlyFriends && _this.isFriend))
                    && !_this.isCurrentUserUnavailable;
            });
            this.showFeedBackForm = function () {
                window["AppComponents"].FeedbackForm.show(_this.userId, "User", _this.profileUrl);
            };
            this.userId = data.userId;
            this.privacySendPM = PrivacyPrivateMessage[data.privacyPrivateMessage];
            this.unavailableMessage(data.unavailableMessage);
            this.subscriptionInfo = data.subscriptionInfo;
            this.isFriend = data.subscriptionInfoWithoutInvisible
                && data.subscriptionInfoWithoutInvisible.targetUserSubscription
                && data.subscriptionInfoWithoutInvisible.targetUserSubscription.isMutual;
            this.isCurrentUserUnavailable = viewModel.isCurrentUserUnavailable;
            this.subscriptionInfoWithoutInvisible = data.subscriptionInfoWithoutInvisible;
            this.profileUrl = data.profileUrl;
            this.ignored(data.ignored);
            this.ignoredByUser = data.ignoredByUser;
            this.lastActivity(moment(data.lastActivity));
            this.isVerified = data.isVerified;
            setInterval(function () {
                _this.lastActivity(_this.lastActivity());
            }, 15000);
            this.allowSendPM.subscribe(function () {
                setTimeout(function () {
                    viewModel.resizeControls(true);
                }, 100);
            });
        }
        PrivateChat.prototype.lastActivityFromNow = function () {
            var lastActivity = this.lastActivity();
            return lastActivity.fromNow();
        };
        return PrivateChat;
    }(BaseChat));
    var GroupChat = (function (_super) {
        __extends(GroupChat, _super);
        function GroupChat(data, viewModel) {
            _super.call(this, data, viewModel);
            this.allowSendPM = ko.pureComputed(function () {
                return true;
            });
        }
        return GroupChat;
    }(BaseChat));
    var PMContact = (function () {
        function PMContact(data, viewModel) {
            var _this = this;
            this.isActive = ko.pureComputed(function () {
                var currentChat = _this.viewModel.currentChat();
                if (currentChat && !currentChat.isGroup) {
                    return _this.userId === currentChat["userId"];
                }
                return false;
            });
            this.userId = data.userId;
            this.fio = data.fio;
            this.userName = "@" + data.userName;
            this.avatarUrl = data.avatarUrl;
            this.isVerified = data.isVerified;
            this.viewModel = viewModel;
        }
        return PMContact;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.currentUserId = window["app"].userId;
            this.moreData = true;
            this.page = 1;
            this.recentChatsPage = 1;
            this.recentChats = ko.observableArray();
            this.orderedRecentChats = ko.pureComputed(function () {
                return _.sortBy(_this.recentChats(), function (x) {
                    return moment(x.lastMessageSentTime()).toDate();
                }).reverse();
            });
            this.moreChats = ko.observable(true);
            this.searchResults = ko.observableArray();
            this.isCurrentUserUnavailable = false;
            this.currentChat = ko.observable(null);
            this.isLoading = ko.observable(false);
            this.messages = ko.observableArray();
            this.redactorInitialized = ko.observable(false);
            this.isConnected = ko.observable(false);
            this.messageText = ko.observable("").extend({
                max: {
                    params: 20000,
                    message: "Длина поля должна быть не больше {0} символов."
                }
            });
            this.selectedMessages = ko.observableArray();
            this.froalaOptions = {
                heightMin: 75,
                heightMax: 150,
                charCounterMax: 20000,
                placeholder: "Текст сообщения",
                pastePlain: true,
                toolbarBottom: true,
                imageDefaultDisplay: "block",
                imageEditButtons: ["imageReplace", "imageAlign", "imageDisplay",
                    "imageAlt", "imageSize", "imageRemove"],
                imageDefaultAlign: "left",
                toolbarButtons: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "insertLink", "insertImage", "fullscreen"
                ],
                toolbarButtonsMD: [
                    "bold", "italic", "underline", "strikeThrough", "|",
                    "quote", "emoticons", "insertLink", "insertImage", "fullscreen"
                ],
                toolbarButtonsSM: [
                    "bold", "italic", "underline", "strikeThrough", "|", "quote", "insertLink", "insertImage", "fullscreen", "|", "undo", "redo"
                ],
                toolbarButtonsXS: [
                    "bold", "|", "quote", "insertLink", "insertImage", "fullscreen", "|", "undo", "redo"
                ]
            };
            this.sendBtnDisable = ko.computed(function () {
                var text = _this.messageText();
                if ($.fn.froalaEditor === undefined) {
                    return false;
                }
                ;
                var charCount = $(".send-message-form textarea").froalaEditor("charCounter.count");
                return charCount === 0 || charCount.length === 0 || !_this.isConnected();
            });
            this.processing = ko.observable(false);
            this.searchQuery = ko.observable("");
            this.searchQueryWithRateLimit = ko.computed(function () {
                var query = _this.searchQuery();
                if (query.length > 0) {
                    ajaxUtils_1.AjaxUtils.get("pm/searchContacts", { query: query })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            alert(result.messages[0]);
                            return;
                        }
                        var contacts = _.map(result.data, function (i) {
                            return new PMContact(i, _this);
                        });
                        _this.searchResults(contacts);
                        setTimeout(function () {
                            $("#search-results").nanoScroller();
                        }, 0);
                    });
                }
            }).extend({
                rateLimit: {
                    timeout: 1500,
                    method: "notifyAtFixedRate"
                }
            });
            this.deleteMessages = function () {
                if (_this.isLoading())
                    return;
                var messages = _this.selectedMessages();
                var ids = _.map(messages, function (x) { return x.id; });
                _this.showModal({
                    title: "Требуется подтверждение",
                    message: "\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B, \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435(-\u044F)?",
                    type: modalDialog_1.ModalType.Confirm,
                    onSubmit: function () {
                        _this.isLoading(true);
                        ajaxUtils_1.AjaxUtils.post("pm/deleteMessages", { ids: ids })
                            .done(function (result) {
                            if (!result.isSuccessful) {
                                alert(result.messages[0]);
                                return;
                            }
                            _.each(messages, function (x) {
                                x.state("DeletedByUser");
                                x.allowEdit(false);
                            });
                            _this.selectedMessages([]);
                            _this.modal.hide();
                        }).always(function () {
                            _this.isLoading(false);
                        });
                    }
                });
            };
            this.selectChat = function (chat) {
                _this.currentChat(chat);
                _this.messages([]);
                _this.selectedMessages([]);
                _this.page = 1;
                _this.loadMessages(true);
                chat.unreadCount(0);
            };
            this.selectContact = function (contact) {
                var chat = _.find(_this.recentChats(), function (c) {
                    return !c.isGroup && c.userId === contact.userId;
                });
                var refreshMessages = function () {
                    _this.messages([]);
                    _this.page = 1;
                    _this.loadMessages(true);
                };
                if (chat) {
                    _this.currentChat(chat);
                    chat.unreadCount(0);
                    refreshMessages();
                }
                else {
                    ajaxUtils_1.AjaxUtils.get("pm/privateChat", { userId: contact.userId })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            alert(result.messages[0]);
                            return;
                        }
                        var chat = new PrivateChat(result.data, _this);
                        _this.recentChats.push(chat);
                        _this.currentChat(chat);
                        refreshMessages();
                    });
                }
            };
            this.sendMessage = function () {
                var messageText = _this.messageText();
                if (messageText === null || messageText === undefined || messageText.length === 0) {
                    return;
                }
                if (_this.processing()) {
                    return;
                }
                var chat = _this.currentChat();
                if (!chat)
                    return;
                _this.processing(true);
                var messageData = {
                    chatId: chat.id,
                    text: messageText
                };
                var editingMessage = _this.editingMessage();
                if (editingMessage) {
                    messageData.id = editingMessage.id;
                }
                ajaxUtils_1.AjaxUtils.post("pm/sendMessage", messageData).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    //if (editingMessage && chat.lastMessageId ==) {
                    //    chat.lastMessageText(StringUtils.clearFromTags(messageText));
                    //}
                    _this.messageText("");
                    _this.editingMessage(null);
                    _this.selectedMessages([]);
                }).always(function () {
                    setTimeout(function () {
                        _this.processing(false);
                    }, 100);
                });
            };
            this.selectMessage = function (message, event) {
                if ($(event.target).is("a"))
                    return true;
                if (_this.editingMessage())
                    return true;
                if (!message.allowEdit())
                    return true;
                var alreadySelected = _this.selectedMessages().indexOf(message) !== -1;
                if (alreadySelected) {
                    _this.selectedMessages.remove(message);
                }
                else {
                    _this.selectedMessages.push(message);
                }
            };
            this.clearSelection = function () {
                _this.selectedMessages([]);
            };
            this.showTextForm = ko.pureComputed(function () {
                var chat = _this.currentChat();
                var editingMessage = _this.editingMessage();
                var messages = _this.selectedMessages();
                if (!chat || !chat.allowSendPM() || (chat.unavailableMessage()))
                    return false;
                if (editingMessage)
                    return true;
                return messages.length === 0;
            });
            this.editMessage = function () {
                var selectedMessages = _this.selectedMessages();
                if (selectedMessages.length !== 1)
                    return;
                var messageText = _this.messageText();
                if (messageText && messageText.trim().length > 0) {
                    _this.showModal({
                        title: "Требуется подтверждение",
                        message: "\u0423 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C \u043D\u0435\u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0442\u0435\u0440\u044F\u043D\u043E. \u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C?",
                        type: modalDialog_1.ModalType.Confirm,
                        onSubmit: function () {
                            _this.startEditingMessage();
                            _this.modal.hide();
                        }
                    });
                }
                else {
                    _this.startEditingMessage();
                }
            };
            this.editingMessage = ko.observable();
            this.cancelEditingMessage = function () {
                _this.editingMessage(null);
                _this.messageText("");
                _this.selectedMessages([]);
            };
            this.userAvatarUrl = options.userAvatarUrl;
            this.isCurrentUserUnavailable = options.isCurrentUserUnavailable;
            this.loadRecentChats();
            $(function () {
                _this.$pmMessages = $(".pm-messages");
                _this.$pmMessages.nanoScroller();
                var formHeigth = $(".send-message-form").height();
                _this.messageText.subscribe(function () {
                    var newHeight = $(".send-message-form").height();
                    if (newHeight === formHeigth)
                        return;
                    setTimeout(function () { return _this.resizeControls(); }, 100);
                });
                $(window).on("resize", function () {
                    _this.resizeControls();
                });
                _this.$pmMessages.on("update", function (event, values) {
                    if (_this.moreData && values.position === 0 && !_this.isLoading()) {
                        _this.loadMessages("more");
                    }
                });
            });
        }
        ViewModel.prototype.resizeControls = function (withoutScroll) {
            if (withoutScroll === void 0) { withoutScroll = false; }
            this.$pmMessages = $(".pm-messages");
            if (!this.$pmMessages[0])
                return;
            var formHeight = $("#footer").height();
            var newHeight = $(".dialog").height() - 75 - formHeight;
            this.$pmMessages.css("height", newHeight);
            this.$pmMessages.nanoScroller();
            //this.$pmMessages.nanoScroller({ scroll: "bottom" });
        };
        ViewModel.prototype.initRouting = function () {
            var _this = this;
            var routes = {
                ":id": function (id) {
                    if (_this.currentId == id) {
                        return;
                    }
                    _this.currentId = id;
                    if (typeof id === "string" && id.indexOf("g") === 0) {
                    }
                    else {
                        var userId = parseInt(id);
                        _this.currentChat(null);
                        // Проверяем список чатов
                        var chat = _.find(_this.recentChats(), function (c) {
                            return !c.isGroup && c.userId === userId;
                        });
                        if (chat) {
                            _this.selectChat(chat);
                            return;
                        }
                        // Если не нашли ничего
                        ajaxUtils_1.AjaxUtils.get("pm/privateChat", { userId: userId })
                            .done(function (result) {
                            if (!result.isSuccessful) {
                                alert(result.messages[0]);
                                return;
                            }
                            var chat = new PrivateChat(result.data, _this);
                            _this.recentChats.push(chat);
                            _this.selectChat(chat);
                        });
                    }
                }
            };
            this.router = director.Router(routes);
            this.router.init();
        };
        ViewModel.prototype.onIsOnline = function (userId) {
            _.each(this.recentChats(), function (c) {
                if (!c.isGroup && c.userId === userId) {
                    c.lastActivity(moment.utc());
                }
            });
        };
        ;
        ViewModel.prototype.onNewMessage = function (message) {
            var _this = this;
            var currentChat = this.currentChat();
            var chat = _.find(this.recentChats(), function (c) {
                return c.id === message.chatId;
            });
            if (chat) {
                chat.lastMessageId(message.id);
                chat.lastMessageUserId(message.userId);
                chat.lastMessageText(stringUtils_1.default.clearFromTags(message.text));
                chat.lastMessageSentTime(moment(message.sentTime).toDate());
            }
            // Добавляем сообщение в текущий диалог, и помечаем как прочитанное
            if (currentChat && chat && currentChat.id === chat.id) {
                if (message.userId === this.currentUserId) {
                    message.allowEdit = true;
                }
                this.messages.push(this.toMessage(message));
                setTimeout(function () {
                    _this.$pmMessages.nanoScroller();
                    _this.$pmMessages.nanoScroller({ scroll: "bottom" });
                    var messages = _this.$pmMessages.find(".message");
                    imageZoomUtils_1.default.init(messages[messages.length - 1]);
                }, 50);
                if (message.userId !== this.currentUserId) {
                    ajaxUtils_1.AjaxUtils.post("pm/markAsRead", { id: chat.id });
                }
                return;
            }
            this.reloadNotificationCount();
            if (chat) {
                if (message.userId !== this.currentUserId) {
                    chat.unreadCount(chat.unreadCount() + 1);
                    chat.lastActivity(new Date());
                }
            }
            else {
                if (!message.isGroupChat) {
                    // Если не нашли ничего
                    ajaxUtils_1.AjaxUtils.get("pm/privateChat", { userId: message.userId })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            alert(result.messages[0]);
                            return;
                        }
                        var chat = new PrivateChat(result.data, _this);
                        _this.recentChats.push(chat);
                    });
                }
                else {
                }
            }
        };
        ViewModel.prototype.messageUpdate = function (message) {
            var currentChat = this.currentChat();
            var chat = _.find(this.recentChats(), function (c) {
                return c.id === message.chatId;
            });
            if (currentChat && chat && currentChat.id === chat.id) {
                var messageToUpdate = _.find(this.messages(), function (x) { return x.id === message.id; });
                if (messageToUpdate) {
                    messageToUpdate.text(message.text);
                    messageToUpdate.lastModificationTime(message.lastModificationTime);
                    setTimeout(function () {
                        var messages = $(".message");
                        imageZoomUtils_1.default.init(messages[messages.length - 1]);
                    }, 50);
                }
            }
        };
        ViewModel.prototype.loadRecentChats = function () {
            var _this = this;
            if (!this.moreChats()) {
                return;
            }
            ajaxUtils_1.AjaxUtils.get("pm/recentChats", { page: this.recentChatsPage })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                var chats = _.map(result.data.chats, function (i) {
                    return i.isGroup ? new GroupChat(i, _this) : new PrivateChat(i, _this);
                });
                ko.utils.arrayPushAll(_this.recentChats, chats);
                setTimeout(function () {
                    $(".contact-list").nanoScroller();
                }, 0);
                _this.moreChats(result.data.more);
                _this.recentChatsPage++;
                if (!_this.isConnected()) {
                    var hub = $.connection["notificationHub"];
                    hub.client.chatNewMessage = function (message) {
                        _this.onNewMessage(message);
                        var pmTabId = webSocketUtils_1.default.getPMTabId();
                        if (webSocketUtils_1.default.html5NotificationPermision === "granted"
                            && (app.activePage == null || app.activePage.indexOf("/pm") === -1)
                            && message.userId !== app.userId) {
                            var notification = new Notification("Личное сообщение от " + message.userFIO, {
                                body: stringUtils_1.default.clearFromTags(ko.unwrap(message.text)).replace(/<br\s*[\/]?>/gi, " "),
                                dir: "auto",
                                tag: "PMMessage",
                                icon: app.rootUrl + "dist/images/logo.png"
                            });
                            var url = app.rootUrl + "pm#" + message.userId;
                            if (pmTabId !== null) {
                                notification.onclick = function () {
                                    crosstab.broadcast("focusPage", { url: url }, pmTabId);
                                    notification.close();
                                };
                            }
                            else {
                                notification.onclick = function () {
                                    window.open(url);
                                    notification.close();
                                };
                            }
                        }
                    };
                    hub.client.chatMessageUpdate = function (message) {
                        _this.messageUpdate(message);
                    };
                    hub.client.isOnline = function (message) {
                        _this.onIsOnline(message);
                    };
                    $.connection.hub.start({ transport: ["webSockets", "longPolling"] })
                        .done(function () {
                        _this.isConnected(true);
                        console.log("Connected, transport: " + $.connection.hub.transport.name + ", connection ID: " + hub.connection.id);
                    });
                    $.connection.hub.disconnected(function () {
                        _this.isConnected(false);
                        console.log("Disconnected.");
                        setTimeout(function () {
                            $.connection.hub.start({ transport: ["webSockets", "longPolling"] })
                                .done(function () {
                                _this.isConnected(true);
                                console.log("Connected, transport: " + $.connection.hub.transport
                                    .name + ", connection ID: " + hub.connection.id);
                            });
                        }, 3000);
                    });
                    _this.initRouting();
                }
            });
        };
        ViewModel.prototype.loadMessages = function (scrollDown) {
            var _this = this;
            if (this.currentAjaxRequest) {
                this.currentAjaxRequest.abort();
            }
            var chat = this.currentChat();
            if (!chat)
                return;
            this.isLoading(scrollDown);
            nprogress.start();
            var $lastMessage = $(".message").get(0);
            this.currentAjaxRequest = ajaxUtils_1.AjaxUtils.get("pm/messages", {
                id: chat.id,
                page: this.page
            })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.reloadNotificationCount();
                _this.moreData = result.data.more;
                _this.page++;
                var messages = _.map(result.data.messages, function (i) { return _this.toMessage(i); });
                _.each(messages, function (m) {
                    _this.messages.unshift(m);
                });
                setTimeout(function () {
                    _this.$pmMessages = $(".pm-messages");
                    _this.$pmMessages.nanoScroller();
                    if (scrollDown !== "more") {
                        _this.$pmMessages["imagesLoaded"]()
                            .always(function () {
                            setTimeout(function () {
                                _this.$pmMessages.nanoScroller({ alwaysVisible: true });
                                _this.$pmMessages.nanoScroller({ scroll: "bottom" });
                            }, 100);
                        });
                        _this.$pmMessages.nanoScroller({ scroll: "bottom" });
                    }
                    else {
                        _this.$pmMessages.nanoScroller({ scrollTo: $lastMessage });
                    }
                    _this.isLoading(false);
                    nprogress.done();
                    imageZoomUtils_1.default.init(_this.$pmMessages);
                }, 0);
            });
        };
        ViewModel.prototype.reloadNotificationCount = function () {
            var component = window["AppComponents"].Notifications;
            if (component) {
                component.reload();
            }
        };
        ViewModel.prototype.clearSearchQuery = function () {
            this.searchQuery("");
        };
        ViewModel.prototype.startEditingMessage = function () {
            var _this = this;
            var message = this.selectedMessages()[0];
            var originalText = richContentUtils_1.default.replaceEmoji(message.text());
            this.editingMessage(message);
            setTimeout(function () {
                _this.messageText(originalText);
                $(".send-message-form textarea").froalaEditor("events.focus");
            });
        };
        ViewModel.prototype.toMessage = function (data) {
            data.isMy = data.userId === this.currentUserId;
            data.text = ko.observable(data.text);
            if (data.state === 1) {
                data.state = "Default";
            }
            data.state = ko.observable(data.state);
            data.allowEdit = ko.observable(data.allowEdit);
            data.lastModificationTime = ko.observable(data.lastModificationTime);
            return data;
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/imageZoomUtils":57,"../utils/richContentUtils":67,"../utils/stringUtils":69,"../utils/webSocketUtils":71,"./base/baseViewModel":92,"crosstab":176,"director":186,"imagesloaded":212,"jquery":214,"knockout":191,"lodash":216,"moment":219,"nanoScroller":192,"nprogress":193}],128:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "jquery.countdown", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/windowUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    require("jquery.countdown");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var windowUtils_1 = require("../utils/windowUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 100;
            this.categoryId = ko.observable().extend({
                required: true
            });
            this.title = ko.observable().extend({
                required: true,
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                var characters = title.length;
                return characters + "/" + _this.titleMaxLength;
            });
            this.text = ko.observable().extend({
                required: true
            });
            this.tags = ko.observableArray(this.options.tags || []).extend({
                maxLength: { params: 5, message: "До 5-ти тэгов через запятую, разрешены пробелы" }
            });
            this.tagsSelect2Settings = {
                placeholder: 'До 5 тэгов через запятую...',
                tags: true, ajax: {
                    url: window["app"].rootUrl + "post/searchTags",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [','],
                maximumSelectionLength: 5,
                language: {
                    maximumSelected: function () { return 'Вы можете выбрать не более 5 тэгов.'; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    item.count = item.count || 0;
                    var markup = "<div class='clearfix'>\
                <div class='pull-left'>" + item.text + "</div>\
                <div class='pull-right'>" + item.count + "<div>\
                </div>";
                    return markup;
                }
            };
            this.privacyDisplayId = ko.observable();
            this.privacyDisplayOptions = [
                { id: 1, title: "Все (пост виден в общей ленте)" },
                { id: 2, title: "Друзья и подписчики" },
                { id: 3, title: "Только друзья" }
            ];
            this.privacyCommentsId = ko.observable();
            this.privacyCommentsOptions = ko.observableArray();
            this.postEditorsEnabled = ko.observable(this.options.postEditorIds && this.options.postEditorIds.length > 0);
            this.postEditorIds = ko.observableArray(this.options.postEditorIds || []);
            this.postEditors = ko.observableArray(this.options.postEditors);
            this.postEditorIdsSelect2Settings = {
                placeholder: "Выберите от одного до трех редакторов",
                minimumResultsForSearch: 5,
                maximumSelectionLength: 3,
                language: {
                    maximumSelected: function () { return "Вы можете выбрать не более трех редакторов."; }
                },
                ajax: {
                    url: window["app"].rootUrl + "account/searchUser",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            userId: _this.options.authorId,
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.userId,
                                    text: x.fio + " @" + x.userName
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                }
            };
            this.id = options.id;
            this.titleInit = options.titleInit;
            this.postEditorsEnabled(options.postEditorsEnabled);
            setTimeout(function () {
                _this.initValidation();
            }, 100);
            ko.computed(function () {
                var title = _this.title() || "";
                if (stringUtils_1.default.compareWithoutLineBreaks(title, _this.titleInit)) {
                    windowUtils_1.default.setDirty();
                }
                else {
                    windowUtils_1.default.setDirty(false);
                }
            });
            this.postEditorsEnabled.subscribe(function (value) {
                $("#postEditorsEnabledInfo").collapse(value ? "show" : "hide");
            });
            if (options.nextGlobalFlowPostTime) {
                $("#globalFlowPostCountDown")["countdown"](moment(options.nextGlobalFlowPostTime).toDate(), function (event) {
                    $(this).html(event.strftime("%H:%M:%S"));
                });
            }
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
            this.privacyDisplayId.subscribe(function (id) {
                if (id === 1) {
                    _this.privacyCommentsOptions([
                        { id: 1, title: "Все" },
                        { id: 2, title: "Только друзья" },
                        { id: 0, title: "Никто" }
                    ]);
                    if (_this.privacyCommentsId() === 2) {
                        _this.privacyCommentsId(1);
                    }
                }
                else if (id === 2) {
                    _this.privacyCommentsOptions([
                        { id: 1, title: "Друзья и подписчики" },
                        { id: 2, title: "Только друзья" },
                        { id: 0, title: "Никто" }
                    ]);
                    if (_this.privacyCommentsId() === 2) {
                        _this.privacyCommentsId(1);
                    }
                }
                else {
                    _this.privacyCommentsOptions([
                        { id: 2, title: "Только друзья" },
                        { id: 0, title: "Никто" }
                    ]);
                }
            });
            this.privacyDisplayId(options.privacyDisplayId);
            setTimeout(function () {
                _this.privacyCommentsId(options.privacyCommentsId);
            });
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        ViewModel.prototype.showDeletePostModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление поста",
                message: "Вы точно хотите удалить этот пост?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("post/delete", {
                        id: _this.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                    });
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/stringUtils":69,"../utils/windowUtils":72,"./base/validatedViewModel":93,"jquery":214,"jquery.countdown":189,"knockout":191,"lodash":216,"moment":219}],129:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "../utils/ajaxUtils", "./commentsView", "../utils/socialUtils", "../utils/richContentUtils", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var commentsView_1 = require("./commentsView");
    var socialUtils_1 = require("../utils/socialUtils");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            socialUtils_1.default.init();
            richContentUtils_1.default.processHtml(".full-post");
            this.initVotesInfo();
            this.loadComments(null, null, false);
        }
        ViewModel.prototype.initVotesInfo = function () {
            var _this = this;
            var el = $("#postVotes");
            el.find(".dropdown-toggle").on("click", function (e) {
                var container = $(e.target).parent();
                var spinner = container.find(".widget-spinner");
                if (spinner.length == 0) {
                    return;
                }
                spinner.show();
                ajaxUtils_1.AjaxUtils.get("post/votes", { postId: _this.options.postId })
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    container.find(".dropdown-menu").html(result.data.html);
                    dateTimeUtils_1.default.displayTime(container);
                })
                    .always(function () {
                    spinner.hide();
                });
            });
        };
        return ViewModel;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../utils/richContentUtils":67,"../utils/socialUtils":68,"./commentsView":99,"jquery":214}],130:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "./base/baseViewModel", "../utils/richContentUtils", "../utils/postUtils", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var postUtils_1 = require("../utils/postUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.startDate = ko.observable(moment().startOf("day").add(-6, "days"));
            this.endDate = ko.observable(moment().endOf("day"));
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = this.options.query;
            this.dateRangePickerOptions = {
                ranges: {
                    'За сегодня': [moment().startOf("day"), moment().endOf("day")],
                    'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                    'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")]
                }
            };
            this.isLoading = ko.observable(true);
            this.filterData = ko.computed(function () {
                var filterData = {
                    from: moment(_this.startDate()).format("YYYY-MM-DD"),
                    to: moment(_this.endDate()).format("YYYY-MM-DD")
                };
                return filterData;
            });
            if (options.startDate && options.endDate) {
                this.startDate(moment(options.startDate).local().startOf("day"));
                this.endDate(moment(options.endDate).local().endOf("day"));
            }
            richContentUtils_1.default.processHtml(".posts");
            setTimeout(function () {
                _this.filterData.subscribe(function (data) {
                    var filterData = $.param(data);
                    var url = window.location.pathname + "?" + filterData;
                    _this.redirectToPage(url);
                });
            }, 100);
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (_this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                return false;
            });
            $('#search-results').on('pjax:success', function () {
                dateTimeUtils_1.default.displayTime($("#search-results"));
            });
            postUtils_1.default.startViewStatsCollector();
            richContentUtils_1.default.processHtml("#search-results");
        }
        ViewModel.prototype.clearSearchQuery = function () {
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                $(".search-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"../utils/postUtils":64,"../utils/richContentUtils":67,"./base/baseViewModel":92,"jquery":214,"knockout":191,"moment":219}],131:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93}],132:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel", "../utils/richContentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            richContentUtils_1.default.processHtml(".award-description");
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/richContentUtils":67,"./base/validatedViewModel":93}],133:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/baseViewModel", "../utils/richContentUtils", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = this.options.query || "";
            this.isClearBtn = false;
            this.showDeleted = ko.observable();
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (!_this.isClearBtn || _this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                _this.isClearBtn = false;
                return false;
            });
            richContentUtils_1.default.processHtml("#search-results");
            setTimeout(function () {
                _this.showDeleted.subscribe(function () {
                    $(".search-form").submit();
                });
            }, 200);
            this.showDeleted(this.options.showDeleted);
            $('#search-results').on('pjax:success', function () {
                dateTimeUtils_1.default.displayTime($("#search-results"));
            });
        }
        ViewModel.prototype.clearSearchQuery = function () {
            var _this = this;
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                _this.isClearBtn = true;
                $(".search-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"../utils/richContentUtils":67,"./base/baseViewModel":92,"jquery":214,"knockout":191}],134:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel", "../utils/commentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var commentUtils_1 = require("../utils/commentUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            commentUtils_1.default.init(null);
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/commentUtils":49,"./base/validatedViewModel":93}],135:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "drop", "./base/validatedViewModel", "../utils/ajaxUtils", "../utils/richContentUtils", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var Drop = require("drop");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = ko.observable("");
            this.isClearBtn = false;
            this.isEnableSortingToggled = false;
            this.showDeleted = ko.observable();
            this.enableSorting = ko.observable();
            this.currentSortIndex = ko.observable();
            this.newSortIndex = ko.observable();
            this.moveToIndex = function (currentIndex, newIndex) {
                if (_this.processing())
                    return;
                if (isNaN(Number(newIndex)) || newIndex < 0 || isNaN(Number(currentIndex)) || currentIndex < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndex == currentIndex) {
                    _this.closeAllDrop();
                    return;
                }
                _this.reoderWorks(newIndex, currentIndex);
            };
            this.moveTo = function () {
                if (_this.processing())
                    return;
                var newIndex = _this.newSortIndex() - 1, currentIndex = _this.currentSortIndex();
                if (isNaN(Number(newIndex)) || newIndex < 0 || isNaN(Number(currentIndex)) || currentIndex < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndex == currentIndex) {
                    _this.closeAllDrop();
                    return;
                }
                _this.reoderWorks(newIndex, currentIndex);
            };
            this.moveUp = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === 0) {
                    newIndex = _this.options.totalCount - 1;
                }
                else {
                    newIndex--;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.moveDown = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === _this.options.totalCount - 1) {
                    newIndex = 0;
                }
                else {
                    newIndex++;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.currentPage = options.currentPage;
            $(document).off("submit", "form[data-pjax]");
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (!_this.isClearBtn || _this.submitQuery() !== _this.searchQuery()) {
                    _this.submitQuery(_this.searchQuery());
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                _this.isClearBtn = false;
                return false;
            });
            richContentUtils_1.default.processHtml("#search-results");
            setTimeout(function () {
                _this.showDeleted.subscribe(function () {
                    $(".search-form").submit();
                });
                _this.enableSorting.subscribe(function () {
                    _this.isEnableSortingToggled = true;
                    $(".search-form").submit();
                });
            }, 200);
            this.showDeleted(this.options.showDeleted);
            this.enableSorting(this.options.enableSorting);
            this.initChangeOrderDrodown();
            var self = this;
            $('#search-results').on('pjax:success', function () {
                self.initChangeOrderDrodown();
                dateTimeUtils_1.default.displayTime($("#search-results"));
            });
            $('#search-results').on('pjax:beforeSend', function (event, xhr, options) {
                if (self.isEnableSortingToggled) {
                    options.url += "&page=" + _this.currentPage;
                    self.isEnableSortingToggled = false;
                }
            });
        }
        ViewModel.prototype.initChangeOrderDrodown = function () {
            var _this = this;
            var changeOrderDrodown = document.getElementById("work-order-dropdown").innerHTML;
            $(".art-wrapper").each(function (i, el) {
                var $el = $(el), $changeOrderBtn = $el.find(".change-order-btn");
                if (!$changeOrderBtn.length) {
                    return;
                }
                var drop = new Drop({
                    target: $changeOrderBtn[0],
                    content: function () {
                        var $content = $("<div />").html(changeOrderDrodown);
                        ko.applyBindingsToDescendants(_this, $content[0]);
                        return $content[0];
                    },
                    /*openOn: "hover",*/
                    hoverCloseDelay: 150,
                    constrainToScrollParent: true,
                    tetherOptions: {
                        attachment: "top center",
                        targetAttachment: "bottom center",
                        constraints: [
                            {
                                to: "window",
                                attachment: "together",
                                pin: true
                            }
                        ]
                    }
                });
                drop.on("open", function () {
                    var order = JSON.parse($el.attr("data-order"));
                    _this.currentSortIndex(order);
                    _this.newSortIndex(order + 1);
                    $el.addClass('hover');
                    drop.position();
                });
                drop.on("close", function () {
                    $el.removeClass('hover');
                });
                $changeOrderBtn.data("drop", drop);
            });
        };
        ViewModel.prototype.clearSearchQuery = function () {
            var _this = this;
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                _this.isClearBtn = true;
                $(".search-form").submit();
            });
        };
        ViewModel.prototype.reoderWorks = function (newIndex, oldIndex) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("art/reoder", {
                profileId: this.options.profileId,
                newIndex: newIndex,
                oldIndex: oldIndex
            }).done(function (result) {
                if (result.isSuccessful) {
                    _this.closeAllDrop();
                    toastr.success(result.messages[0]);
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.closeAllDrop = function () {
            var drop = $(".drop-enabled").data("drop");
            if (drop) {
                drop.close();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../utils/richContentUtils":67,"./base/validatedViewModel":93,"drop":197,"jquery":214,"knockout":191,"toastr":199}],136:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.enableSorting = ko.observable();
            this.moveUp = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === 0) {
                    newIndex = _this.options.totalCount - 1;
                }
                else {
                    newIndex--;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.moveDown = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === _this.totalCount - 1) {
                    newIndex = 0;
                }
                else {
                    newIndex++;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.totalCount = options.totalCount;
            this.profileId = options.profileId;
            $(document).off("submit", "form[data-pjax]");
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                return false;
            });
            setTimeout(function () {
                _this.enableSorting.subscribe(function () {
                    $(".search-form").submit();
                });
            }, 200);
            this.enableSorting(options.enableSorting);
        }
        ViewModel.prototype.showDeleteSeriesModal = function (id, title) {
            var _this = this;
            this.showModal({
                title: "Удаление цикла произведений",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0446\u0438\u043A\u043B \u00AB" + title + "\u00BB?",
                minWidth: "300px",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("work/series/delete", {
                        id: id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success(result.messages[0]);
                            _this.modal.hide();
                            $("#series_" + id).fadeOut("normal", function () {
                                $(this).remove();
                            });
                            _this.reloadPage();
                        }
                    });
                }
            });
        };
        ViewModel.prototype.reoderWorks = function (newIndex, oldIndex) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/series/reoder", {
                profileId: this.profileId,
                newIndex: newIndex,
                oldIndex: oldIndex
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success(result.messages[0]);
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"toastr":199}],137:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "drop", "./base/validatedViewModel", "../utils/ajaxUtils", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var Drop = require("drop");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = ko.observable("");
            this.isClearBtn = false;
            this.isEnableSortingToggled = false;
            this.currentSortIndex = ko.observable();
            this.newSortIndex = ko.observable();
            this.showDeleted = ko.observable();
            this.enableSorting = ko.observable();
            this.moveToIndex = function (currentIndex, newIndex) {
                if (_this.processing())
                    return;
                if (isNaN(Number(newIndex)) || newIndex < 0 || isNaN(Number(currentIndex)) || currentIndex < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndex == currentIndex) {
                    _this.closeAllDrop();
                    return;
                }
                ;
                _this.reoderWorks(newIndex, currentIndex);
            };
            this.moveTo = function () {
                if (_this.processing())
                    return;
                var newIndex = _this.newSortIndex() - 1, currentIndex = _this.currentSortIndex();
                if (isNaN(Number(newIndex)) || newIndex < 0 || isNaN(Number(currentIndex)) || currentIndex < 0) {
                    alert('Значение должно быть числом');
                    return;
                }
                if (newIndex == currentIndex) {
                    _this.closeAllDrop();
                    return;
                }
                _this.reoderWorks(newIndex, currentIndex);
            };
            this.moveUp = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === 0) {
                    newIndex = _this.options.totalCount - 1;
                }
                else {
                    newIndex--;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.moveDown = function (index) {
                if (_this.processing())
                    return;
                index = ko.unwrap(index);
                var newIndex = index;
                if (index === _this.totalCount - 1) {
                    newIndex = 0;
                }
                else if (index === _this.pageSize - 1) {
                    if (_this.totalCount > _this.pageSize) {
                        newIndex++;
                    }
                    else {
                        newIndex = 0;
                    }
                }
                else {
                    newIndex++;
                }
                _this.reoderWorks(newIndex, index);
            };
            this.totalCount = options.totalCount;
            this.pageSize = options.pageSize;
            this.profileId = options.profileId;
            this.currentPage = options.currentPage;
            $(document).off("submit", "form[data-pjax]");
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (!_this.isClearBtn || _this.submitQuery() !== _this.searchQuery()) {
                    _this.submitQuery(_this.searchQuery());
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                _this.isClearBtn = false;
                return false;
            });
            setTimeout(function () {
                _this.showDeleted.subscribe(function () {
                    $(".search-form").submit();
                });
                _this.enableSorting.subscribe(function () {
                    _this.isEnableSortingToggled = true;
                    $(".search-form").submit();
                });
            }, 200);
            this.showDeleted(this.options.showDeleted);
            this.enableSorting(this.options.enableSorting);
            this.initChangeOrderDrodown();
            var self = this;
            $('#search-results').on('pjax:success', function () {
                self.initChangeOrderDrodown();
                dateTimeUtils_1.default.displayTime($("#search-results"));
            });
            $('#search-results').on('pjax:beforeSend', function (event, xhr, options) {
                if (self.isEnableSortingToggled) {
                    options.url += "&page=" + _this.currentPage;
                    self.isEnableSortingToggled = false;
                }
            });
        }
        ViewModel.prototype.reoderWorks = function (newIndex, oldIndex) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/reoder", {
                profileId: this.profileId,
                newIndex: newIndex,
                oldIndex: oldIndex
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success(result.messages[0]);
                    _this.closeAllDrop();
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.initChangeOrderDrodown = function () {
            var _this = this;
            var changeOrderDrodown = document.getElementById("work-order-dropdown").innerHTML;
            $(".book-row").each(function (i, el) {
                var $el = $(el), $changeOrderBtn = $el.find(".change-order-btn");
                if (!$changeOrderBtn.length) {
                    return;
                }
                var drop = new Drop({
                    target: $changeOrderBtn[0],
                    content: function () {
                        var $content = $("<div />").html(changeOrderDrodown);
                        ko.applyBindingsToDescendants(_this, $content[0]);
                        return $content[0];
                    },
                    /*openOn: "hover",*/
                    hoverCloseDelay: 150,
                    constrainToScrollParent: true,
                    tetherOptions: {
                        attachment: "top center",
                        targetAttachment: "bottom center",
                        constraints: [
                            {
                                to: "window",
                                attachment: "together",
                                pin: true
                            }
                        ]
                    }
                });
                drop.on("open", function () {
                    var order = JSON.parse($el.attr("data-order"));
                    _this.currentSortIndex(order);
                    _this.newSortIndex(order + 1);
                    drop.position();
                });
                $changeOrderBtn.data("drop", drop);
            });
        };
        ViewModel.prototype.clearSearchQuery = function () {
            var _this = this;
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                _this.isClearBtn = true;
                $(".search-form").submit();
            });
        };
        ViewModel.prototype.showWorkLink = function (link) {
            prompt("Для того чтобы скопировать ссылку нажмите Ctrl+C, а потом Enter.", link);
        };
        ViewModel.prototype.closeAllDrop = function () {
            var drop = $(".drop-enabled").data("drop");
            if (drop) {
                drop.close();
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"./base/validatedViewModel":93,"drop":197,"jquery":214,"knockout":191,"toastr":199}],138:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/richContentUtils", "./commentsView", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var scriptjs = require("scriptjs");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var commentsView_1 = require("./commentsView");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.userNoteMaxLength = 500;
            this.processing = ko.observable(false);
            this.userNote = ko.observable().extend({
                maxLength: this.userNoteMaxLength
            });
            this.userNoteHint = ko.pureComputed(function () {
                var userNote = _this.userNote() || "";
                return userNote.length + "/" + _this.userNoteMaxLength;
            });
            this.profileId = options.profileId;
            this.userNote(options.userNote);
            richContentUtils_1.default.processHtml(".about-me");
            scriptjs([(app.rootUrl + "distCommon/vendor/slick/1.6.0/slick.min.js")], function () {
                _this.initWorksCarousel("#works");
            });
            this.loadComments(null, null, false);
            $(".autoresize-textarea").each(function () {
                this.style.height = this.scrollHeight + "px";
                this.style.overflowY = "hidden";
            }).on("input", function () {
                this.style.height = "auto";
                this.style.height = this.scrollHeight + "px";
            });
        }
        ViewModel.prototype.saveUserNote = function (btn) {
            var _this = this;
            var $btn = $(btn);
            if (this.processing())
                return;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post('profile/updateUserNote', {
                targetUserId: this.profileId,
                note: this.userNote()
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success(result.messages[0]);
                }
                else {
                    alert(result.messages[0]);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.initWorksCarousel = function (id) {
            var $carousel = $(id);
            $carousel.slick({
                slidesToShow: 4,
                slidesToScroll: 4,
                adaptiveHeight: true,
                touchMove: false,
                responsive: [
                    {
                        breakpoint: 1200,
                        settings: {
                            slidesToShow: 3,
                            slidesToScroll: 3
                        }
                    }
                ]
            });
            $(id).css("height", "auto");
        };
        return ViewModel;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/richContentUtils":67,"./commentsView":99,"jquery":214,"knockout":191,"scriptjs":194,"toastr":199}],139:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "drop", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var Drop = require("drop");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.showFilters = ko.observable(this.options.showFilters);
            this.readingCount = ko.observable();
            this.savedCount = ko.observable();
            this.finishedCount = ko.observable();
            this.likedCount = ko.observable();
            this.marksCount = ko.observable();
            this.purchasedCount = ko.observable();
            this.dislikedCount = ko.observable();
            this.allCount = ko.observable();
            this.genre = ko.observable();
            this.state = ko.observable();
            this.form = ko.observable();
            this.format = ko.observable();
            this.isDefaultFilter = ko.observable(true);
            this.isLoading = ko.observable(false);
            this.toggleShowFilters = function () {
                _this.showFilters(!_this.showFilters());
                if (_this.showFilters()) {
                    $("#showFilters").addClass("in");
                }
                else {
                    $("#showFilters").removeClass("in");
                }
            };
            this.tabs = {
                reading: {
                    title: "Читаю / слушаю",
                    icon: "icon-2-library-reading"
                },
                saved: {
                    title: "Отложено на потом",
                    icon: "icon-2-clock"
                },
                finished: {
                    title: "Прочитано",
                    icon: "icon-2-library-finished"
                },
                disliked: {
                    title: "Не нравится",
                    icon: "icon-eye-slash"
                },
                none: {
                    icon: "icon-ellipsis"
                }
            };
            this.selectedWork = ko.observable();
            this.updateWorkState = function (newState) {
                if (_this.isLoading())
                    return;
                _this.isLoading(true);
                var work = _this.selectedWork();
                var $el = $("#work-" + work.id), $btn = $el.find("[data-library-state]");
                $btn.attr("disabled", "disabled").addClass("is-loading");
                ajaxUtils_1.AjaxUtils.post("work/updateLibrary", {
                    ids: [work.id],
                    state: newState
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    if (work.state !== newState) {
                        if (newState !== "none") {
                            var newStateObs = newState.toLowerCase() + "Count";
                            _this[newStateObs](_this[newStateObs]() + 1);
                            toastr.success("\u0412\u044B \u043F\u0435\u0440\u0435\u043C\u0435\u0441\u0442\u0438\u043B\u0438 \u043A\u043D\u0438\u0433\u0443 \u0432 \u0441\u043F\u0438\u0441\u043E\u043A \u00AB" + _this.tabs[newState].title + "\u00BB");
                            $btn.parent().attr("data-hint", _this.tabs[newState].title);
                        }
                        else {
                            toastr.success("Вы удалили книгу из библиотеки");
                            $btn.parent().attr("data-hint", "");
                        }
                        if (work.state !== "none") {
                            var oldStateObs = work.state + "Count";
                            _this[oldStateObs](_this[oldStateObs]() - 1);
                        }
                    }
                    $btn.find("i").removeClass(_this.tabs[work.state].icon)
                        .addClass(_this.tabs[newState].icon);
                    work.state = newState;
                    $el.attr("data-work", ko.toJSON(work));
                    $btn.data("drop").close();
                })
                    .always(function () {
                    $btn.removeAttr("disabled").removeClass("is-loading");
                    _this.isLoading(false);
                });
            };
            this.toggleMark = function (mark) {
                if (_this.isLoading())
                    return;
                _this.isLoading(true);
                var work = _this.selectedWork();
                var $el = $("#work-" + work.id), $btn = $el.find("[data-library-marks]");
                $btn.attr("disabled", "disabled")
                    .addClass("is-loading")
                    .html("");
                var isActive = work.marks.indexOf(mark) === -1;
                ajaxUtils_1.AjaxUtils.post("work/mark", {
                    workId: work.id,
                    isActive: isActive,
                    mark: mark
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    if (result.data.marks && result.data.marks.length) {
                        var activeMark = _.find(_this.options.allMarks, function (m) { return m.enumValue === result.data.marks[0]; });
                        var imgUrl = (app.rootUrl || "/") + "distCommon/emoji/" + activeMark.code + ".svg";
                        var code = "&#x" + activeMark.code;
                        $btn.html("<img src=\"" + imgUrl + "\" alt=\"" + code + "\" />");
                        $btn.parent().attr("data-hint", activeMark.title);
                    }
                    else {
                        $btn.html("<i class=\"icon-2-sparkling\"></i>");
                        $btn.parent().attr("data-hint", "Реакции");
                    }
                    if (work.marks().length > 0 && result.data.marks.length === 0) {
                        _this.marksCount(_this.marksCount() - 1);
                    }
                    else if (work.marks().length === 0 && result.data.marks.length > 0) {
                        _this.marksCount(_this.marksCount() + 1);
                    }
                    work.marks(result.data.marks);
                    $el.attr("data-work", ko.toJSON(work));
                }).always(function () {
                    $btn.removeAttr("disabled")
                        .removeClass("is-loading");
                    _this.isLoading(false);
                });
            };
            this.toggleLike = function () {
                if (_this.isLoading())
                    return;
                _this.isLoading(true);
                var work = _this.selectedWork();
                var $el = $("#work-" + work.id), $btn = $el.find("[data-library-state]");
                $btn.attr("disabled", "disabled").addClass("is-loading");
                var isLiked = !work.isLiked;
                ajaxUtils_1.AjaxUtils.post("work/like", {
                    targetId: work.id,
                    isLiked: isLiked
                }).done(function (result) {
                    if (!result.isSuccessful) {
                        alert(result.messages[0]);
                        return;
                    }
                    if (isLiked) {
                        toastr.success("Вы вернули отметку «Нравится»");
                    }
                    else {
                        toastr.success("Вы убрали отметку «Нравится»");
                    }
                    work.isLiked = isLiked;
                    $el.attr("data-work", ko.toJSON(work));
                    _this.selectedWork(work);
                    _this.likedCount(_this.likedCount() + (isLiked ? 1 : -1));
                }).always(function () {
                    $btn.removeAttr("disabled")
                        .removeClass("is-loading");
                    _this.isLoading(false);
                });
            };
            var initialized = false;
            this.userId = options.userId;
            this.activeTab = options.activeTab;
            this.readingCount(options.readingCount);
            this.savedCount(options.savedCount);
            this.finishedCount(options.finishedCount);
            this.dislikedCount(options.dislikedCount);
            this.likedCount(options.likedCount);
            this.purchasedCount(options.purchasedCount);
            this.marksCount(options.marksCount);
            this.allCount(options.allCount);
            this.defaultFilter = options.defaultFilter;
            ko.computed(function () {
                var genre = _this.genre(), state = _this.state(), form = _this.form(), format = _this.format(), activeTab = _this.activeTab;
                _this.isDefaultFilter(_this.defaultFilter.state == state
                    && _this.defaultFilter.form == form
                    && _this.defaultFilter.format == format
                    && (!genre || genre.length == 0));
                if (!initialized) {
                    return;
                }
                var params = {};
                if (genre) {
                    params.genre = genre;
                }
                if (state) {
                    params.state = state;
                }
                if (form) {
                    params.form = form;
                }
                if (format) {
                    params.format = format;
                }
                if (_this.options.selectedMark !== 0) {
                    params.mark = _this.options.selectedMark;
                }
                var url = app.rootUrl + ("u/" + options.userName + "/library/" + activeTab + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" }).done(function () {
                    _this.initLibraryDropdowns();
                });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            this.initLibraryDropdowns();
        }
        ViewModel.prototype.initLibraryDropdowns = function () {
            var _this = this;
            if (!this.options.currentUser)
                return;
            var stateTemplateMarkup = document.getElementById("library-state-dropdown").innerHTML;
            var marksTemplateMarkup = document.getElementById("library-marks-dropdown").innerHTML;
            $(".bookcard").each(function (i, el) {
                var $el = $(el), $stateBtn = $el.find("[data-library-state]"), $marksBtn = $el.find("[data-library-marks]");
                _this.initDropdown($el, $stateBtn, stateTemplateMarkup);
                _this.initDropdown($el, $marksBtn, marksTemplateMarkup, function ($content) {
                    $content.find(".work-mark-button img")
                        .on("mouseover", function (e) {
                        var $img = $(e.target);
                        $img.attr("src", $img.attr("data-animated-src"));
                    })
                        .on("mouseout", function (e) {
                        var $img = $(e.target);
                        $img.attr("src", $img.attr("data-src"));
                    });
                });
            });
        };
        ViewModel.prototype.initDropdown = function ($el, $btn, template, postProcessFunc) {
            var _this = this;
            if (postProcessFunc === void 0) { postProcessFunc = null; }
            if (!$btn.length) {
                return;
            }
            var drop = new Drop({
                target: $btn[0],
                content: function () {
                    var $content = $("<div />").html(template);
                    ko.applyBindingsToDescendants(_this, $content[0]);
                    if (postProcessFunc) {
                        setTimeout(function () {
                            postProcessFunc($content);
                        }, 100);
                    }
                    return $content[0];
                },
                /*openOn: "hover",*/
                hoverCloseDelay: 150,
                constrainToScrollParent: true,
                tetherOptions: {
                    attachment: "top center",
                    targetAttachment: "bottom center",
                    constraints: [
                        {
                            to: "window",
                            attachment: "together",
                            pin: true
                        }
                    ]
                }
            });
            $btn.addClass("btn-tether-drop");
            drop.on("open", function () {
                var work = JSON.parse($el.attr("data-work"));
                work.marks = ko.observableArray(work.marks || []);
                _this.selectedWork(work);
                drop.position();
                $btn.addClass("open");
            });
            drop.on("close", function () {
                $btn.removeClass("open");
            });
            $btn.data("drop", drop);
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"drop":197,"jquery":214,"knockout":191,"lodash":216,"toastr":199}],140:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.viewMode = ko.observable();
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var view = _this.viewMode();
                if (!initialized) {
                    return;
                }
                var params = {};
                var formUrlPart = "";
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (options.form !== "any") {
                    formUrlPart = options.form;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                var url = app.rootUrl + ("u/" + options.username + "/works?" + $.param(params));
                $.pjax({ url: url, container: "#profile-work-search-results", fragment: "#profile-work-search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],141:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.email = ko.observable().extend({
                required: true,
                email: true
            });
            this.stage = ko.observable("welcome");
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        ViewModel.prototype.onSubmitSucess = function (result, formElement) {
            if (this.stage() === "welcome") {
                this.stage("promt");
            }
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    ;
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"knockout":191}],142:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "./base/validatedViewModel", "../utils/socialUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var socialUtils_1 = require("../utils/socialUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.result = {
                "1": 0,
                "2": 0,
                "3": 0,
                "4": 0,
                "5": 0,
                "6": 0,
                "7": 0,
                "8": 0,
                "9": 0,
                "10": 0,
                "11": 0
            };
            this.questionIndex = ko.observable(1);
            this.quizResult = ko.observable();
            this.questions = [
                {
                    title: "Как ты относишься к работе в команде?",
                    hasImage: false,
                    answers: [
                        { text: "Вместе всегда веселей!", s: [2, 8, 9] },
                        { text: "Предпочитаю роль лидера.", s: [3] },
                        { text: "Присоединюсь, если мне это будет выгодно.", s: [7] },
                        { text: "Никак. Я как кот, гуляю сам по себе.", s: [1, 4, 5, 6, 10, 11] }]
                },
                {
                    title: "Какое из этих блюд тебе ближе остальных?",
                    hasImage: true,
                    answers: [
                        { text: "Борщ", img: "food/borscht.jpg", s: [3] },
                        { text: "Гамбургер", img: "food/hamburger.jpg", s: [2, 5, 6, 7] },
                        { text: "Омар", img: "food/lobster.jpg", s: [1, 10] },
                        { text: "Пельмешки", img: "food/pelmeni.jpg", s: [4, 8, 9, 11] },
                        { text: "Пирожки", img: "food/pies.jpg", s: [3] },
                        { text: "Мидии", img: "food/mussels.jpg", s: [1, 10] },
                        { text: "Пицца", img: "food/pizza.jpg", s: [2, 5, 6, 7] },
                        { text: "Шаве́рма", img: "food/shawarma.jpg", s: [4, 8, 9, 11] }]
                },
                {
                    title: "Каковы твои сильные черты?",
                    hasImage: false,
                    answers: [
                        { text: "Честь и достоинство для меня не пустые слова. Я всегда за справедливость.", s: [2, 9] },
                        { text: "Я иду к своей цели несмотря ни на что и обязательно добьюсь результата.", s: [1, 3, 6, 7] },
                        { text: "У меня хорошо работает голова. Обычно планирую свои действия заранее.", s: [5, 8, 10] },
                        { text: "Я смелый и независимый.", s: [4, 11] }]
                },
                {
                    title: "Так, хорошо. А теперь скажи, что тебе в себе не нравится?",
                    hasImage: false,
                    answers: [
                        { text: "Вспыльчивость. Иногда так сложно не поддаться эмоциям!", s: [1, 3, 11] },
                        { text: "Порой я бываю черезчур мягким и нерешительным.", s: [2, 5, 6] },
                        { text: "Склонность к авантюрам. Вечно ищу приключения себе на ... голову.", s: [4, 8, 9] },
                        { text: "У меня нет времени на самокопание.", s: [7, 10] }]
                },
                {
                    title: "Какое твое любимое оружие?",
                    hasImage: false,
                    answers: [
                        { text: "Холодное — мечи, кинжалы, ножи.", s: [3, 4, 6, 7, 11] },
                        { text: "Огнестрел — винтовки и пистолеты.", s: [5] },
                        { text: "Магия.", s: [2, 8, 9, 10] },
                        { text: "Я не нуждаюсь в оружии.", s: [1] }]
                },
                {
                    title: "Тебе выпал шанс расправиться с врагом, как поступишь?",
                    hasImage: false,
                    answers: [
                        { text: "Попытаюсь понять и простить.", s: [3, 6] },
                        { text: "Глупых врагов у меня нет, а два умных человека всегда смогут договориться.", s: [2, 5, 9] },
                        { text: "Неважно, как я его убью, главное, чтобы меня при этом никто не заподозрил.", s: [7, 8] },
                        { text: "Отрублю ему хвост по самую голову... раза три, для верности.", s: [1, 4, 10, 11] }]
                },
                {
                    title: "На дороге лежит битком набитый деньгами кошелек, что выберешь?",
                    hasImage: false,
                    answers: [
                        { text: "Пусть и дальше себе лежит — пройду мимо.", s: [1, 2, 5, 7, 9] },
                        { text: "Нужно попытаться найти владельца, конечно.", s: [3, 10] },
                        { text: "Заберу себе, деньги лишними не бывают.", s: [4, 6, 8, 11] }]
                },
                {
                    title: "Неожиданно рядом с тобой начинается потасовка: семеро против пятерых, твои действия?",
                    hasImage: false,
                    answers: [
                        { text: "Помогу тем, кто в меньшинстве.", s: [2, 3, 6, 9] },
                        { text: "Зависит от настроения: могу присоединиться, а могу и мимо пройти.", s: [1, 4, 8] },
                        { text: "Пройду мимо, мне не нужны лишние проблемы.", s: [10, 11] },
                        { text: "Устрою тотализатор и заработаю на ставках!", s: [] }]
                },
                {
                    title: "Друг вероломно предал тебя, как поступишь?",
                    hasImage: false,
                    answers: [
                        { text: "Вычеркну из списка друзей и забуду о его существовании.", s: [1, 2, 5, 8] },
                        { text: "Попытаюсь понять причину предательства. Просто так друзья не продают.", s: [3, 6, 10] },
                        { text: "Буду долго переживать страдать. Как он мог так поступить... :(", s: [] },
                        { text: "Отомщу так, чтобы надолго запомнил.", s: [4, 11] }]
                },
                {
                    title: "Как ты обычно одеваешься?",
                    hasImage: false,
                    answers: [
                        { text: "Необычно, ярко, вызывающе.", s: [1, 4, 10] },
                        { text: "Что первым найду, то и надену.", s: [2, 11] },
                        { text: "Люблю удобную и практичную одежду.", s: [3, 5, 6, 8] },
                        { text: "Максимально неброско, мне незачем привлекать внимание.", s: [9] }]
                },
                {
                    title: "Ну и последний вопрос. Представь, что выдался свободный денек. Какие планы?",
                    hasImage: false,
                    answers: [
                        {
                            text: "Соберу вещи, разыщу пару друзей, и вместе мы отправимся куда-нибудь " +
                                "прочь из города. Пикник — что может быть лучше?", s: [1]
                        },
                        { text: "Самое время заняться собой. Пределов совершенству быть не может!", s: [2, 5, 7, 8, 11] },
                        {
                            text: "Камин, плед и бокал чего-нибудь согревающего. Можно, наконец, спокойно собраться " +
                                "с мыслями и проанализировать текущую ситуацию.", s: [3, 6, 10]
                        },
                        { text: "Отдохну, высплюсь как следует, поиграю в компьютерные игры или схожу в гости к знакомым.", s: [4, 9] }]
                }];
            this.repeat = function () {
                var owl = $("#quiz-carousel").data("owlCarousel");
                owl.goTo(0);
                _this.questionIndex(1);
                _this.result = {
                    "1": 0,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0,
                    "10": 0,
                    "11": 0
                };
            };
            this.answerClick = function (answer) {
                _.each(answer.s, function (id) {
                    _this.result[id]++;
                });
                if (_this.questionIndex() === _this.questions.length) {
                    var results = _.map(_this.result, function (x) { return x; });
                    var max = _.max(results);
                    var indexes = [];
                    _.each(results, function (c, i) {
                        if (c === max) {
                            indexes.push(i + 1);
                        }
                    });
                    _.shuffle(indexes);
                    _this.calculateResult(indexes[0]);
                }
                else {
                    setTimeout(function () { _this.questionIndex(_this.questionIndex() + 1); }, 200);
                }
                _this.nextSlide();
            };
            this.calculateResult(11);
            setTimeout(function () {
                var $carousel = $("#quiz-carousel");
                $carousel["owlCarousel"]({
                    items: 1,
                    itemsDesktopSmall: [979, 1],
                    itemsTablet: [768, 1],
                    itemsMobile: [479, 1],
                    rewindNav: false,
                    addClassActive: true,
                    transitionStyle: "goDown",
                    pagination: false,
                    mouseDrag: false,
                    touchDrag: false
                });
            }, 100);
        }
        ViewModel.prototype.nextSlide = function () {
            var owl = $("#quiz-carousel").data("owlCarousel");
            owl.next();
        };
        ViewModel.prototype.calculateResult = function (index) {
            switch (index) {
                case 1:
                    this.quizResult({
                        title: "Ты — фройляйн Рита",
                        description: "Сильный человек, несогласный жить по чужим правилам. Несколько эгоцентричный, " +
                            "за стараниями произвести нужный эффект не всегда задумывается, " +
                            "кому и зачем это нужно. Но искренний и готовый до конца отстаивать свою собственную правду.",
                        img: "frojljajnRita.png",
                        workId: 167
                    });
                    break;
                case 2:
                    this.quizResult({
                        title: "Ты — Лин",
                        description: "Чуждая этому миру, но готовая признать его родным. Дружба для тебя ценнее всего, ты стремишься " +
                            "к знаниям и веришь в людей. Твоя цель – остаться собой, несмотря ни на что. " +
                            "Тебя гложут сомнения, однако ты не пройдешь мимо несправедливости. " +
                            "Вероломство, алчность, тщеславие – даже враги согласятся, что это – не о тебе.",
                        img: "Lin.png",
                        workId: 121
                    });
                    break;
                case 3:
                    this.quizResult({
                        title: "Ты — Родомир",
                        description: "Честь и достоинство для тебя не просто слова. Ты никогда не пройдешь мимо несправедливости и" +
                            " всегда защитишь слабого. Семья для тебя самое важное в жизни. Если кому-то хватит " +
                            "глупости ей угрожать, он будет беспощадно уничтожен без права на капитуляцию. " +
                            "Так что лучше сто раз подумать, прежде чем называться твоим врагом.",
                        img: "Rodomir.png",
                        workId: 155
                    });
                    break;
                case 4:
                    this.quizResult({
                        title: "Ты — Виктор Франкенштейн",
                        description: "Падший Синигами и любимец Безумия. Неординарное поведение и безудержное любопытство ведут " +
                            "тебя в неизвестность, а ты и рад этому. Хоть твоё психологическое состояние постоянно страдает от " +
                            "внутренних противоречий, голоса в голове и извечной мании преследования, это не ослабляет ни " +
                            "твоей жажды приключений, ни радости от изучения нового мира и раскрытия тайн, что хранятся в нём.",
                        img: "ViktorFrankenshtejn.png",
                        workId: 144
                    });
                    break;
                case 5:
                    this.quizResult({
                        title: "Ты — Сергей Романов",
                        description: "Внешне — обычный человек. Но никто, кроме самых близких, не знает, насколько " +
                            "в тебе сильна тяга к исследованию мира, к новым горизонтам, к самопознанию. Однако ты не ветреная " +
                            "личность, у тебя всегда есть запасной план, надёжная опора, место, куда можно вернуться, где можно " +
                            "спрятаться. Ты — призма из чистейшего оптического стекла, в которой окружающая действительность распадается " +
                            "на яркие цвета, интересные подробности и новые детали. Именно благодаря этим, довольно простым человеческим качествам, " +
                            "у тебя есть шанс стать избранным, прикоснуться к древней тайне, найти то, что ты так давно искал.",
                        img: "SergejRomanov.png",
                        workId: 387
                    });
                    break;
                case 6:
                    this.quizResult({
                        title: "Ты — Ингер Готтшальк",
                        description: "Одинокий волк, выискивающий овец заблудших. Праздные компании и увеселения – не для тебя. " +
                            "Твоя жизнь подчинена великой цели, и в ее достижении ты привык полагаться на свои силы. Ты не жесток – ты справедлив. " +
                            "И, что бы о тебе ни говорили, в твоей груди бьется самое большое и самое доброе сердце.",
                        img: "IngerGottshalk.png",
                        workId: 456
                    });
                    break;
                case 7:
                    this.quizResult({
                        title: "Ты — Лилиит",
                        description: "Ты хочешь, чтобы окружающие тебя люди всегда были рядом и поддерживали, но " +
                            "частенько получаешь нож в спину. Ты стремишься стать сильнее, чтобы защитить друзей и прожить в большом и страшном мире. " +
                            "Твой меч - твое оружие и твой заработок. А какой охотник не может хорошо продать свой товар? Ты всегда в прибыли.",
                        img: "Liliit.png",
                        workId: 507
                    });
                    break;
                case 8:
                    this.quizResult({
                        title: "Ты — Тенки Ли",
                        description: " Ты знаешь жизнь со всех её сторон и не упустишь шанса вскочить удаче на загривок. " +
                            "Природное обаяние не оставляет тебя без внимания девушек, а простой открытый характер - без дружбы мужчин. " +
                            "Ты - королевский маг, тёмный, черпаешь силу в глубине своей души и в поступках руководствуешься только личными соображениями.",
                        img: "TenkiLi.png",
                        workId: 506
                    });
                    break;
                case 9:
                    this.quizResult({
                        title: "Ты — Рена",
                        description: "Молодая ведьма, призвание которой – помогать людям. Немного самоуверенная, " +
                            "довольно безрассудная, готовая сорваться с места в любой момент " +
                            "и броситься к цели. Тебя трудно переубедить и сбить с пути. " +
                            "Твоя опора – семья. Любовь? Однажды ты поверишь в нее и жизнь станет ярче.",
                        img: "Rena.png",
                        workId: 508
                    });
                    break;
                case 10:
                    this.quizResult({
                        title: "Ты — Харэ",
                        description: "Ты коварный Волшебник Измерения, который исполняя людские желания прокладывает " +
                            "путь к пробуждению тьмы и хаоса. Твоя магия времени и измерений пронизывает все миры. " +
                            "Ты не остановишься ни перед чем, чтобы добиться цели, принеся в жертву своей цели множество жизней.",
                        img: "Harje.png",
                        workId: 463
                    });
                    break;
                case 11:
                    this.quizResult({
                        title: "Ты — Дио",
                        description: "Одинокий и беспощадный. Ты привык верить только себе и полагаешься лишь на собственные силы. " +
                            "Воля - твое второе имя, и ради победы ты будешь драться до последнего. " +
                            "Но никогда не пойдешь на подлость - ты выше этого.",
                        img: "Dio.png",
                        workId: 25
                    });
                    break;
            }
            setTimeout(function () {
                socialUtils_1.default.init();
            }, 200);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/socialUtils":68,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216}],143:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "./base/validatedViewModel", "../utils/socialUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var socialUtils_1 = require("../utils/socialUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.result = {
                "1": 0,
                "2": 0,
                "3": 0,
                "4": 0,
                "5": 0,
                "6": 0,
                "7": 0,
                "8": 0,
                "9": 0,
                "10": 0,
                "11": 0
            };
            this.questionIndex = ko.observable(1);
            this.quizResult = ko.observable();
            this.questions = [
                {
                    title: "В новом мире ты человек?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Да", s: [1, 6, 7, 8, 9, 10, 11] },
                        { id: 2, text: "Поначалу был им", s: [5, 4, 2] },
                        { id: 3, text: "В реале человек, в виртуале - нет", s: [] },
                        { id: 4, text: "Затрудняюсь ответить", s: [] },
                        { id: 5, text: "Для некоторых я перестал им быть", s: [3] },
                        { id: 6, text: "Пф… почему Я, высшее существо, должен опускаться до какого-то там человека?", s: [] },
                        { id: 7, text: "Нечто иное, странное", s: [] }]
                }, {
                    title: "Какой тип боя ты предпочитаешь?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Только мечи! Только хардкор!", s: [10, 4, 1] },
                        { id: 2, text: "Наконечник стрелы - это последнее, что ты увидишь", s: [] },
                        { id: 3, text: "Я тихонько подойду сзади и нарисую тебе кровавую улыбку", s: [] },
                        { id: 4, text: "Как тебе мой метеоритный дождь?", s: [5, 6] },
                        { id: 5, text: "У меня есть способности за гранью человеческих, но это точно не магия", s: [7, 8, 9, 3, 4, 1] },
                        { id: 6, text: "Мои способности рождены технологиями, а не магией, но я способен надрать задницу любому Гендальфу", s: [] },
                        { id: 7, text: "Я не уверен, что это можно назвать магией", s: [2, 11] }]
                }, {
                    title: "Твой мир - реален, или виртуален?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Реален", s: [1, 3, 4, 6, 7, 9] },
                        { id: 2, text: "Виртуален", s: [5] },
                        { id: 3, text: "Мой мир уже давно не игра!", s: [] },
                        { id: 4, text: "Я живу в двух мирах сразу", s: [10] },
                        { id: 5, text: "Мой то реален, но большую часть жизни я зависаю в виртуальности", s: [] },
                        { id: 6, text: "Реальность и виртуальность давно перемешались", s: [] },
                        { id: 7, text: "Виртуальность - это единственная реальность мира", s: [11] },
                        { id: 8, text: "Я не уверен до конца, реален ли мой мир", s: [8, 2] }]
                }, {
                    title: "Ты герой, злодей, или нечто иное?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Я совершенно точно герой: ни дня без подвига", s: [6, 7] },
                        { id: 2, text: "Я самый настоящий злодей", s: [] },
                        { id: 3, text: "Я скорее эгоист, чем злодей", s: [] },
                        { id: 4, text: "Я пофигист - делайте что хотите, я тут веселюсь!", s: [2] },
                        { id: 5, text: "Не лезу в герои, но делаю то, что считаю правильным", s: [1, 3, 4, 5, 8, 9, 10] },
                        { id: 6, text: "Я делец. Добро, зло - лишь бы приносило полновесную прибыль", s: [] },
                        { id: 7, text: "Я творец и художник. И добро, и зло - лишь краски многогранного мира", s: [] },
                        { id: 8, text: "Что если зло, а что есть добро? Давайте обсудим?", s: [11] }]
                }, {
                    title: "В чём твоя цель в этом мире?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Выжить!", s: [] },
                        { id: 2, text: "Золото! Нужно больше золота!", s: [] },
                        { id: 3, text: "Мировое господство, конечно же!", s: [] },
                        { id: 4, text: "Мир во всём мире, добро и радужные пони", s: [1, 3, 7] },
                        { id: 5, text: "Я убиваю чудовищ...", s: [2, 6, 10] },
                        { id: 6, text: "Мне бы выжить, а там разберусь", s: [4, 5, 8, 9, 11] }]
                }, {
                    title: "Вы одиночка, или всегда в кругу друзей?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Одинокий волк", s: [2, 5, 9] },
                        { id: 2, text: "Есть парочка верных друзей", s: [1, 3, 4, 6, 7, 11] },
                        { id: 3, text: "У меня друг, но такой, что перевернёт ради меня мир", s: [] },
                        { id: 4, text: "Бегаю с кланом", s: [8, 10] },
                        { id: 5, text: "Путешествую в компании недругов. Вот такой я оригинал", s: [] },
                        { id: 6, text: "Я скорее в компании питомцев, рабов и призванных существ", s: [] }]
                }, {
                    title: "Вы везунчик, или всего добиваетесь трудом?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Мне благоволят боги. И богини. Особенно богини", s: [] },
                        { id: 2, text: "Моя прописка по паспорту - остров невезения. Всего добиваюсь сам", s: [1, 6] },
                        { id: 3, text: "Отхватил как-то могущественный артефакт. (Не рояль!!!) Или пару. Или тройку. Кто считает? А так все сам", s: [2, 5] },
                        { id: 4, text: "Случайно не прозевал счастье и сумел многого добиться", s: [7, 8] },
                        { id: 5, text: "Мне почему-то всегда все помогают", s: [3] },
                        { id: 6, text: "Везение уже то, что я хотя бы жив!", s: [4, 9, 10] }]
                }, {
                    title: "Что ты думаешь о любви?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Именно ради нее, если понадобится, я уничтожу этот мир!", s: [] },
                        { id: 2, text: "Да-а-а... Каждый день. Три раза минимум! Со всем, что движется", s: [] },
                        { id: 3, text: "Тянки лесом!", s: [11] },
                        { id: 4, text: "Всё ещё в поисках...", s: [] },
                        { id: 5, text: "Любовь - обман для легковерных идиотов. Секс правит миром. Даёшь гарем на четыреста мест!", s: [] },
                        { id: 6, text: "Моя любовь стоит рядом и подаёт патроны", s: [1, 4, 5, 10] },
                        { id: 7, text: "Любовь - это здорово, но стоит ли слишком много говорить о ней вслух?", s: [2, 3, 6, 7, 8, 9] }]
                }, {
                    title: "Ты можешь менять форму?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Конечно!", s: [2, 3, 5, 6] },
                        { id: 2, text: "Нет", s: [1, 7, 8, 9, 10, 11] },
                        { id: 3, text: "Даже несколько!", s: [4] },
                        { id: 4, text: "Пока только учусь", s: [] },
                        { id: 5, text: "Когда я пьян, я кунг-фу Панда!", s: [] }]
                }, {
                    title: "Внезапно у вас появляется способность становится невидимым. Чем займемся?",
                    hasImage: false,
                    answers: [
                        { id: 1, text: "Наведаюсь в ближайший банк и разбогатею", s: [] },
                        { id: 2, text: "Теперь можно подглядывать за девушками в душе!", s: [] },
                        { id: 3, text: "Я буду применять свою новую способность только во благо", s: [1, 3, 11] },
                        { id: 4, text: "Невидимость? А можно все посмотреть?", s: [5, 10] },
                        { id: 5, text: "В смысле появляется? А когда её успели отнять?", s: [2, 4, 6, 7, 8, 9] }]
                }];
            this.repeat = function () {
                var owl = $("#quiz-carousel").data("owlCarousel");
                owl.goTo(0);
                _this.questionIndex(1);
                _this.result = {
                    "1": 0,
                    "2": 0,
                    "3": 0,
                    "4": 0,
                    "5": 0,
                    "6": 0,
                    "7": 0,
                    "8": 0,
                    "9": 0,
                    "10": 0,
                    "11": 0
                };
            };
            this.answerClick = function (answer) {
                _.each(answer.s, function (id) {
                    _this.result[id]++;
                });
                if (_this.questionIndex() === _this.questions.length) {
                    var results = _.map(_this.result, function (x) { return x; });
                    var max = _.max(results);
                    var indexes = [];
                    _.each(results, function (c, i) {
                        if (c === max) {
                            indexes.push(i + 1);
                        }
                    });
                    _.shuffle(indexes);
                    _this.calculateResult(indexes[0]);
                }
                else {
                    setTimeout(function () { _this.questionIndex(_this.questionIndex() + 1); }, 200);
                }
                _this.nextSlide();
            };
            this.calculateResult(11);
            setTimeout(function () {
                var $carousel = $("#quiz-carousel");
                $carousel["owlCarousel"]({
                    items: 1,
                    itemsDesktopSmall: [979, 1],
                    itemsTablet: [768, 1],
                    itemsMobile: [479, 1],
                    rewindNav: false,
                    addClassActive: true,
                    transitionStyle: "goDown",
                    pagination: false,
                    mouseDrag: false,
                    touchDrag: false
                });
            }, 100);
        }
        ViewModel.prototype.nextSlide = function () {
            var owl = $("#quiz-carousel").data("owlCarousel");
            owl.next();
        };
        ViewModel.prototype.calculateResult = function (index) {
            switch (index) {
                case 1:
                    this.quizResult({
                        title: "Ты — Окава Кеншин",
                        description: "Меня зовут - Окава Кеншин и не говорите потом, что не расслышали",
                        img: "okava_kenshin.jpg",
                        vkImg: "okava_kenshin2.jpg",
                        workId: 8595
                    });
                    break;
                case 2:
                    this.quizResult({
                        title: "Ты — Варг",
                        description: "Пиво было, но крафтовое, а я к такому всегда относился с подозрением",
                        img: "varg.jpg",
                        vkImg: "varg2.jpg",
                        workId: 13288
                    });
                    break;
                case 3:
                    this.quizResult({
                        title: "Ты — Рэми",
                        description: "И не надо на меня так смотреть, не надо жалеть, жалость убивает.",
                        img: "remi.jpg",
                        vkImg: "remi2.jpg",
                        workId: 7003
                    });
                    break;
                case 4:
                    this.quizResult({
                        title: "Ты — Саргон",
                        description: "Ты чертовски ошибся с выбором противника. Ибо я - не человек. Я - Силпат.",
                        img: "sargon.jpg",
                        vkImg: "sargon2.jpg",
                        workId: 12790
                    });
                    break;
                case 5:
                    this.quizResult({
                        title: "Ты — Махан",
                        description: "Щаз все брошу и думать буду",
                        img: "mahan.jpg",
                        vkImg: "mahan2.jpg",
                        workId: 15254
                    });
                    break;
                case 6:
                    this.quizResult({
                        title: "Ты — Лумумба",
                        description: "Вдруг бывает только взрыв, когда о растяжку запнешься.",
                        img: "lumumba.jpg",
                        vkImg: "lumumba2.jpg",
                        workId: 15032
                    });
                    break;
                case 7:
                    this.quizResult({
                        title: "Ты — Фил Панфилов",
                        description: "Больше огня под ногами твоих врагов, испытуемый!",
                        img: "fil.jpg",
                        vkImg: "fil2.jpg",
                        workId: 8553
                    });
                    break;
                case 8:
                    this.quizResult({
                        title: "Ты — Док",
                        description: "Но… после смерти можно жить в покое, жить дальше после смерти, в своих детях.",
                        img: "dok.jpg",
                        vkImg: "dok2.jpg",
                        workId: 13544
                    });
                    break;
                case 9:
                    this.quizResult({
                        title: "Ты — Найкрас",
                        description: "Да прибудет пемброк!",
                        img: "naikras.jpg",
                        vkImg: "naikras2.jpg",
                        workId: 10561
                    });
                    break;
                case 10:
                    this.quizResult({
                        title: "Ты — Зловреда",
                        description: "У вас есть целая жизнь, чтобы работать, а дети будут маленькими всего один раз",
                        img: "zlovreda.jpg",
                        vkImg: "zlovreda2.jpg",
                        workId: 13680
                    });
                    break;
                case 11:
                    this.quizResult({
                        title: "Ты — Норман",
                        description: "Живи, демоны тебя раздери! У меня ещё никто не умирал!",
                        img: "norman.jpg",
                        vkImg: "norman2.jpg",
                        workId: 15125
                    });
                    break;
            }
            setTimeout(function () {
                socialUtils_1.default.init();
            }, 200);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/socialUtils":68,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216}],144:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "screenfull", "../utils/ajaxUtils", "../utils/localStorageUtils", "../components/modalDialog", "../utils/metrikaUtils", "../utils/imageZoomUtils", "./base/baseViewModel", "../../app/utils/cookieUtils", "../../app/utils/readingProgressUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var screenfull = require("screenfull");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var metrikaUtils_1 = require("../utils/metrikaUtils");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var cookieUtils_1 = require("../../app/utils/cookieUtils");
    var readingProgressUtils_1 = require("../../app/utils/readingProgressUtils");
    var Settings = (function () {
        function Settings() {
        }
        return Settings;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.minFontSize = 1;
            this.maxFontSize = 30;
            this.minFieldSize = 1;
            this.maxFieldSize = 7;
            this.minLineHeight = 1;
            this.maxLineHeight = 5;
            this.minBrightness = 1;
            this.maxBrightness = 5;
            this.$reader = $("#reader");
            this.$textWrapper = $(".text-wrapper");
            this.isLoading = ko.observable(true);
            this.isInit = false;
            this.showUnauthorizedForm = ko.observable(false);
            this.showSuspendedForm = ko.observable(false);
            this.showBuyForm = ko.observable(false);
            this.showUnadultedForm = ko.observable(false);
            this.showContent = ko.pureComputed(function () {
                return !_this.showUnauthorizedForm()
                    && !_this.showSuspendedForm()
                    && !_this.showBuyForm()
                    && !_this.showUnadultedForm();
            });
            this.readerMode = ko.observable("scroll");
            this.visibleLeftPanel = ko.observable(false);
            this.visibleRightPanel = ko.observable(false);
            this.controlsIsVisible = ko.observable(true);
            this.isDisabled = ko.pureComputed(function () {
                return (_this.visibleLeftPanel() || _this.visibleRightPanel());
            });
            this.currentChapterId = ko.observable();
            this.loginUrl = ko.pureComputed(function () {
                return app.rootUrl + "account/login?returnUrl=" + encodeURIComponent(app.rootUrl + "reader/" + _this.workId + "/" + _this.currentChapterId());
            });
            this.registerUrl = ko.pureComputed(function () {
                return app.rootUrl + "account/register?returnUrl=" + encodeURIComponent(app.rootUrl + "reader/" + _this.workId + "/" + _this.currentChapterId());
            });
            // Используются только в режиме Книги
            this.width = ko.observable();
            this.height = ko.observable();
            this.scrollWidth = ko.observable();
            this.singleColumn = ko.observable(true);
            this.page = ko.observable(0);
            // Используются в режиме Scroll
            this.chapters = ko.observableArray();
            this.totalTextLength = ko.pureComputed(function () {
                var length = 0;
                _.each(_this.chapters(), function (c) {
                    length += c.textLength;
                });
                return length;
            });
            this.readTextLength = ko.observable(0);
            this.isFullScreenMode = ko.observable(false);
            this.fontList = ["Roboto", "Verdana", "Georgia", "Arial", "Alegreya", "Times New Roman", "Comfortaa", "Fira Sans", "PT Sans"];
            this.fontListIsOpen = ko.observable(false);
            this.fontPickerIcon = ko.pureComputed(function () {
                return _this.fontListIsOpen() ? "fa-angle-up" : "fa-angle-down";
            });
            this.fontSize = ko.observable();
            this.fieldSize = ko.observable();
            this.lineHeight = ko.observable();
            this.fontFamily = ko.observable();
            this.brightness = ko.observable();
            this.customColorScheme = ko.observable();
            this.customFontColor = ko.observable();
            this.customBackgroundColor = ko.observable();
            this.hyphenation = ko.observable();
            this.bodyClass = ko.pureComputed(function () {
                var brightness = _this.brightness();
                var customColorScheme = _this.customColorScheme();
                var customFontColor = _this.customFontColor();
                var customBackgroundColor = _this.customBackgroundColor();
                var css = "";
                if (customColorScheme) {
                    var color = customBackgroundColor.substring(1); // strip #
                    var rgb = parseInt(color, 16); // convert rrggbb to decimal
                    var r = (rgb >> 16) & 0xff; // extract red
                    var g = (rgb >> 8) & 0xff; // extract green
                    var b = (rgb >> 0) & 0xff; // extract blue
                    var luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; // per ITU-R BT.709
                    if (luma < 40) {
                        css += "dark-theme";
                    }
                    else {
                        css += "light-theme";
                    }
                    $("body").css("color", customFontColor);
                    $("body").css("background-color", customBackgroundColor);
                }
                else {
                    css += "brightness-" + brightness;
                    $("body").css("color", "");
                    $("body").css("background-color", "");
                }
                if (_this.readerMode() === "scroll") {
                    css += " scroll-mode";
                }
                if (_this.showBuyForm()) {
                    css += " buy-form-active";
                    $("html").css({
                        overflow: "auto"
                    });
                }
                else {
                    $("html").css({
                        overflow: "hidden"
                    });
                }
                return css;
            });
            this.textWrapperClass = ko.pureComputed(function () {
                var fieldSize = _this.fieldSize();
                return "field-size-" + fieldSize;
            });
            this.columnGap = ko.pureComputed(function () {
                return Math.ceil(_this.width() * 0.065);
            });
            this.columnWidth = ko.pureComputed(function () {
                if (_this.singleColumn()) {
                    return _this.width() - _this.columnGap();
                }
                return (_this.width() - _this.columnGap()) / 2;
            });
            this.step = ko.pureComputed(function () {
                var singleStep = _this.columnWidth() + _this.columnGap();
                return _this.singleColumn() ? singleStep + _this.columnGap() : singleStep * 2;
            });
            this.totalPages = ko.pureComputed(function () {
                var value = _this.scrollWidth() / _this.step();
                if (!_this.singleColumn()) {
                    value *= 2;
                }
                return Math.ceil(value);
            });
            this.singleEndPage = ko.pureComputed(function () {
                return _this.totalPages() % 2 === 1;
            });
            this.endOfChapter = ko.pureComputed(function () {
                var page = _this.currentPage(), totalPages = _this.totalPages();
                if (_this.singleColumn()) {
                    return page === totalPages;
                }
                if (_this.singleEndPage()) {
                    return page === totalPages;
                }
                return page + 1 >= totalPages;
            });
            this.currentPage = ko.pureComputed(function () {
                var value = _this.page(), totalPages = _this.totalPages();
                if (!_this.singleColumn()) {
                    value = value * 2;
                }
                value++;
                if (value > totalPages) {
                    value = totalPages;
                    if (!_this.singleEndPage()) {
                        value--;
                    }
                    _this.page(Math.ceil(totalPages / 2) - 1);
                }
                return value;
            });
            this.currentChapter = ko.pureComputed(function () {
                var id = _this.currentChapterId();
                return _.find(_this.chapters(), function (c) {
                    return c.id === id;
                });
            });
            this.chapterInfo = ko.pureComputed(function () {
                var leftPages = _this.totalPages() - _this.currentPage() - 1;
                if (_this.workForm === "Story") {
                    if (leftPages <= 0) {
                        return "Конец";
                    }
                    return "\u041E\u0441\u0442\u0430\u043B\u043E\u0441\u044C " + leftPages + " \u0441\u0442\u0440.";
                }
                if (leftPages <= 0) {
                    return "Конец главы";
                }
                return "\u041E\u0441\u0442\u0430\u043B\u043E\u0441\u044C \u0432 \u0433\u043B\u0430\u0432\u0435: " + leftPages + " \u0441\u0442\u0440.";
            });
            this.chapterInfoTitle = ko.pureComputed(function () {
                if (_this.singleColumn()) {
                    return _this.currentPage() + " \u0438\u0437 " + _this.totalPages();
                }
                if (_this.currentPage() === _this.totalPages()) {
                    return _this.currentPage() + " \u0438\u0437 " + _this.totalPages();
                }
                return _this.currentPage() + "-" + (_this.currentPage() + 1) + " \u0438\u0437 " + _this.totalPages();
            });
            this.readingInfo = ko.pureComputed(function () {
                var percent = _this.progressPercent().toFixed(1);
                return percent + "%";
            });
            this.footerTitle = ko.pureComputed(function () {
                var chapter = _this.currentChapter();
                if (chapter) {
                    var title = _this.workTitle + ", " + _this.authorName;
                    if (_this.workForm !== "Story") {
                        title = title + ", " + chapter.title;
                    }
                    return title;
                }
                return "";
            });
            this.offset = ko.pureComputed(function () {
                var scrollWidth = _this.scrollWidth(), value = _this.page() * _this.step();
                if (value > scrollWidth) {
                    return scrollWidth - _this.step();
                }
                return value;
            });
            this.lastNormalPercent = 0;
            this.progressPercent = ko.pureComputed(function () {
                var currentChapter = _this.currentChapter();
                if (!currentChapter)
                    return 0;
                var chapterReadTextLength = currentChapter.textLength * _this.chapterProgressPercent();
                var totalReadTextLength = _this.readTextLength() + chapterReadTextLength;
                var percent = totalReadTextLength * 100 / _this.totalTextLength();
                if (_this.isLoading()) {
                    percent = _this.lastNormalPercent;
                }
                else {
                    _this.lastNormalPercent = percent;
                }
                return percent;
            });
            this.prevChapter = ko.pureComputed(function () {
                var index = _this.chapters().indexOf(_this.currentChapter());
                index--;
                if (index < 0)
                    return null;
                return _this.chapters()[index];
            });
            this.nextChapter = ko.pureComputed(function () {
                var chapters = _this.chapters();
                var index = _this.chapters().indexOf(_this.currentChapter());
                index++;
                if (index >= chapters.length)
                    return null;
                return _this.chapters()[index];
            });
            this.progressUpdated = true;
            this.progressPercentComputed = ko.pureComputed(function () {
                _this.progressUpdated = false;
                return _this.progressPercent();
            }).extend({
                rateLimit: {
                    timeout: app.isAuthenticated ? 3000 : 30000,
                    method: app.isAuthenticated ? "notifyWhenChangesStop" : "notifyAtFixedRate"
                }
            });
            this.textContainerStyle = ko.pureComputed(function () {
                if (_this.showBuyForm())
                    return "";
                var columnWith = _this.columnWidth() + "px";
                var columnGap = _this.columnGap() + "px";
                var fontSize = 10 + _this.fontSize();
                var lineHeight = 0.9 + _this.lineHeight() * 0.15;
                setTimeout(function () {
                    _this.scrollWidth($("#text-container").get(0).scrollWidth);
                }, 100);
                if (_this.readerMode() === "scroll") {
                    return "font-family: " + _this.fontFamily() + ";\n            line-height: " + lineHeight + "em !important;\n            font-size: " + fontSize + "px";
                }
                return "left: -" + _this.offset() + "px;\n            height: " + _this.height() + "px;\n            -webkit-column-width: " + columnWith + ";\n            -moz-column-width: " + columnWith + ";\n            column-width: " + columnWith + ";\n            -webkit-column-gap: " + columnGap + ";\n            -moz-column-gap: " + columnGap + ";\n            column-gap: " + columnGap + ";\n            font-family: " + _this.fontFamily() + ";\n            line-height: " + lineHeight + "em !important;\n            font-size: " + fontSize + "px";
            });
            this.selectFont = function (font) {
                _this.fontFamily(font);
                _this.toggleFontList();
            };
            this.goToChapter = function (chapter) {
                _this.hideLeftPanel();
                _this.showBuyForm(false);
                _this.showUnauthorizedForm(false);
                _this.showSuspendedForm(false);
                _this.showUnadultedForm(false);
                _this.loadChapter(chapter.id);
            };
            this.hyphenopoly = options.hyphenopoly;
            this.workId = options.workId;
            this.workTitle = options.workTitle;
            this.workForm = options.workForm;
            this.authorName = options.authorName;
            this.chapters(options.chapters);
            this.sessionId = options.sessionId;
            this.nextSeriesWorkId = options.nextSeriesWorkId;
            this.epilog = options.epilog;
            this.loadSettings();
            this.hanleUserInput();
            this.initObservables();
            this.recalculateSize();
            this.initSliders();
            localStorageUtils_1.default.addToList(localStorageUtils_1.default.RecentlyViewedKey, this.workId);
            this.loadChapter(options.chapterId, false, options.chapterProgress);
            setTimeout(function () {
                _this.isInit = true;
            }, 1000);
            this.progressPercentComputed.subscribe(function () {
                _this.updateReadingProgress();
            });
            $(function () {
                $('[data-toggle="tooltip"]').tooltip({
                    placement: "bottom",
                    container: "body"
                });
            });
            try {
                document.addEventListener(screenfull.raw.fullscreenchange, function () {
                    _this.isFullScreenMode(screenfull.isFullscreen);
                });
            }
            catch (ex) {
                // Safari iOS bug
                $("#btnFullScreen").hide();
            }
            this.controlsIsVisible.subscribe(function (isVisible) {
                if (!isVisible) {
                    $('[data-toggle="tooltip"]').tooltip("hide");
                }
            });
            this.isLoading.subscribe(function (value) {
                if (!value && _this.settings.hyphenation) {
                    try {
                        _this.loadHyphenopoly();
                    }
                    catch (ex) {
                        alert("Перенос слов не работает на вашем устройстве!");
                        _this.hyphenation(false);
                        _this.settings.hyphenation = false;
                        localStorageUtils_1.default.set("reader.settings", _this.settings);
                    }
                }
            });
            if (app.userId && options.useReadingProgress) {
                readingProgressUtils_1.default.check(app.userId, this.workId, options.chapterId, options.chapterProgress);
            }
        }
        /** Загрузка переносов в тексте */
        ViewModel.prototype.loadHyphenopoly = function () {
            this.hyphenopoly.config({
                require: {
                    "ru": ""
                },
                setup: {
                    selectors: {
                        "#text-container": {}
                    }
                }
            });
        };
        ViewModel.prototype.initObservables = function () {
            var _this = this;
            if (this.readerMode() === "scroll") {
                this.chapterProgressPercent = ko.observable();
            }
            else {
                this.chapterProgressPercent = ko.pureComputed({
                    read: function () {
                        var offset = _this.offset(), scrollWidth = _this.scrollWidth(), currentChapter = _this.currentChapter();
                        if (!currentChapter)
                            return 0;
                        var chapterPercent = offset / scrollWidth;
                        if (_this.endOfChapter() && currentChapter === _this.chapters()[_this.chapters().length - 1]) {
                            chapterPercent = 100;
                        }
                        return Math.min(1, chapterPercent);
                    },
                    write: function (value) {
                        var scrollWidth = $("#text-container").get(0).scrollWidth, step = _this.step();
                        var offset = scrollWidth * (value / 100);
                        var page = Math.round(offset / step);
                        _this.scrollWidth(scrollWidth);
                        _this.page(page);
                    }
                });
            }
        };
        ViewModel.prototype.hanleUserInput = function () {
            var _this = this;
            $(window).on("resize", function () {
                _this.recalculateSize();
            });
            if (this.readerMode() === "book") {
                $(document).on("keydown.reader", function (e) {
                    switch (e.which) {
                        case 33: // page up
                        case 38:
                            _this.previousPage();
                            break;
                        case 37:
                            if (e.ctrlKey) {
                                _this.goToChapter(_this.prevChapter());
                            }
                            else {
                                _this.previousPage();
                            }
                            break;
                        case 32: // space
                        case 34: // page down
                        case 40:
                            _this.nextPage();
                            break;
                        case 39:
                            if (e.ctrlKey) {
                                _this.goToChapter(_this.nextChapter());
                            }
                            else {
                                _this.nextPage();
                            }
                            break;
                        default:
                            return; // exit this handler for other keys
                    }
                    e.preventDefault(); // prevent the default action (scroll / move caret)
                });
            }
            else {
                var lastAnimationStart = new Date().getTime();
                var allowAnimation = function () { return new Date().getTime() - lastAnimationStart > 150; };
                $(document).on("keydown.reader", function (e) {
                    //отключаем перехват ввода символов с клавиатуры
                    if ($(e.target).is("#text-container") || $(e.target).is("#rewardTitle"))
                        return;
                    switch (e.which) {
                        case 33:
                            if (allowAnimation()) {
                                _this.$reader.animate({ scrollTop: _this.$reader.scrollTop() - $("#app").height() + 70 }, 150);
                                lastAnimationStart = new Date().getTime();
                            }
                            break;
                        case 32: // space
                        case 34:
                            if (allowAnimation()) {
                                _this.$reader.animate({ scrollTop: _this.$reader.scrollTop() + $("#app").height() - 70 }, 150);
                                lastAnimationStart = new Date().getTime();
                            }
                            break;
                        case 40:
                            _this.$reader.scrollTop(_this.$reader.scrollTop() + 40);
                            break;
                        case 38:
                            _this.$reader.scrollTop(_this.$reader.scrollTop() - 40);
                            break;
                        case 35:
                            _this.$reader.animate({ scrollTop: $("#text-container").height() }, "fast");
                            break;
                        case 36:
                            _this.$reader.animate({ scrollTop: 0 }, "fast");
                            break;
                        case 37:
                            if (e.ctrlKey) {
                                _this.goToChapter(_this.prevChapter());
                            }
                            break;
                        case 39:
                            if (e.ctrlKey) {
                                _this.goToChapter(_this.nextChapter());
                            }
                            break;
                        default:
                            return; // exit this handler for other keys
                    }
                    e.preventDefault(); // prevent the default action (scroll / move caret)
                });
            }
            var time = 0;
            var lastScrollPosition = 0;
            if (this.readerMode() === "scroll") {
                this.$reader.on("scroll.reader", function (event) {
                    var scrollTop = _this.$reader.scrollTop();
                    if (scrollTop - lastScrollPosition > 120) {
                        _this.controlsIsVisible(false);
                        lastScrollPosition = scrollTop;
                    }
                    else if (scrollTop - lastScrollPosition < -60) {
                        _this.controlsIsVisible(true);
                        lastScrollPosition = scrollTop;
                    }
                    if ($.now() - time <= 500)
                        return;
                    time = $.now();
                    var height = $("#text-container").height();
                    _this.chapterProgressPercent(scrollTop / height);
                });
            }
            else {
                $(window).on("mousewheel.reader", function (event) {
                    if ($.now() - time <= 500)
                        return;
                    time = $.now();
                    if (event["deltaY"] > 0) {
                        // scroll up
                        _this.previousPage();
                    }
                    else {
                        // scroll down
                        _this.nextPage();
                    }
                });
            }
        };
        ViewModel.prototype.recalculateSize = function () {
            if (this.readerMode() !== "scroll") {
                var width = $("#text-container").width();
                this.width(width);
                this.singleColumn(width < 940);
                this.height(this.$textWrapper.height());
                this.scrollWidth($("#text-container").get(0).scrollWidth);
            }
        };
        ViewModel.prototype.loadSettings = function () {
            var _this = this;
            var settings = localStorageUtils_1.default.get("reader.settings");
            if (settings === null || settings === undefined) {
                settings = {
                    brightness: 5,
                    fontSize: 8,
                    fieldSize: 6,
                    lineHeight: 3,
                    fontFamily: this.fontList[0],
                    readerMode: "scroll",
                    customColorScheme: false,
                    customFontColor: "#444",
                    customBackgroundColor: "#FFFFFF",
                    version: "1.1",
                    hyphenation: false
                };
            }
            if (settings.version === undefined || settings.version === null) {
                settings.fontSize = (settings.fontSize || 4) * 2;
                this.saveSettings();
            }
            else {
                this.settings = settings;
            }
            this.brightness(settings.brightness || 5);
            this.fontSize(settings.fontSize || 8);
            this.fieldSize(settings.fieldSize || 6);
            this.lineHeight(settings.lineHeight || 3);
            this.fontFamily(settings.fontFamily);
            this.readerMode(settings.readerMode || "scroll");
            this.customColorScheme(settings.customColorScheme || false);
            this.hyphenation(settings.hyphenation || false);
            this.customFontColor(settings.customFontColor || "#444");
            this.customBackgroundColor(settings.customBackgroundColor || "#FFFFFF");
            this.brightness.subscribe(function () { return _this.saveSettings(); });
            this.fontSize.subscribe(function () { return _this.saveSettings(); });
            this.fieldSize.subscribe(function () { return _this.saveSettings(); });
            this.lineHeight.subscribe(function () { return _this.saveSettings(); });
            this.fontFamily.subscribe(function () { return _this.saveSettings(); });
            this.customColorScheme.subscribe(function () { return _this.saveSettings(); });
            this.hyphenation.subscribe(function () { return _this.saveSettings(); });
            this.customFontColor.subscribe(function () { return _this.saveSettings(); });
            this.customBackgroundColor.subscribe(function () { return _this.saveSettings(); });
            setTimeout(function () {
                _this.readerMode.subscribe(function () {
                    _this.isLoading(true);
                    _this.saveSettings();
                    _this.fullReloadPage();
                });
            });
        };
        ViewModel.prototype.saveSettings = function () {
            if (this.settings.hyphenation != this.hyphenation()) {
                this.fullReloadPage();
                this.isLoading(true);
            }
            this.settings = {
                brightness: this.brightness(),
                fontSize: this.fontSize(),
                fieldSize: this.fieldSize(),
                lineHeight: this.lineHeight(),
                fontFamily: this.fontFamily(),
                readerMode: this.readerMode(),
                customColorScheme: this.customColorScheme(),
                customFontColor: this.customFontColor(),
                customBackgroundColor: this.customBackgroundColor(),
                version: "1.1",
                hyphenation: this.hyphenation()
            };
            localStorageUtils_1.default.set("reader.settings", this.settings);
        };
        ViewModel.prototype.initSliders = function () {
            var _this = this;
            $("#fontSizeSlider").kendoSlider({
                showButtons: false,
                min: this.minFontSize,
                max: this.maxFontSize,
                largeStep: this.maxFontSize,
                smallStep: 1,
                tickPlacement: "none",
                value: this.fontSize(),
                tooltip: {
                    enabled: false
                },
                slide: function (e) {
                    _this.fontSize(e.value);
                },
                change: function (e) {
                    _this.fontSize(e.value);
                }
            });
            $("#fieldSizeSlider").kendoSlider({
                showButtons: false,
                min: this.minFieldSize,
                max: this.maxFieldSize,
                largeStep: this.maxFieldSize,
                smallStep: 1,
                tickPlacement: "none",
                value: this.fieldSize(),
                tooltip: {
                    enabled: false
                },
                slide: function (e) {
                    _this.fieldSize(e.value);
                },
                change: function (e) {
                    _this.fieldSize(e.value);
                }
            });
            $("#lineHeightSlider").kendoSlider({
                showButtons: false,
                min: this.minLineHeight,
                max: this.maxLineHeight,
                largeStep: this.maxLineHeight,
                smallStep: 1,
                tickPlacement: "none",
                value: this.lineHeight(),
                tooltip: {
                    enabled: false
                },
                slide: function (e) {
                    _this.lineHeight(e.value);
                },
                change: function (e) {
                    _this.lineHeight(e.value);
                }
            });
            $("#brightnessSlider").kendoSlider({
                showButtons: false,
                min: this.minBrightness,
                max: this.maxBrightness,
                largeStep: this.maxBrightness,
                smallStep: 1,
                tickPlacement: "none",
                value: this.brightness(),
                tooltip: {
                    enabled: false
                },
                slide: function (e) {
                    _this.brightness(e.value);
                },
                change: function (e) {
                    _this.brightness(e.value);
                }
            });
            var brightnessSlider = $("#brightnessSlider").data("kendoSlider");
            this.customColorScheme.subscribe(function (enabled) {
                brightnessSlider.enable(!enabled);
            });
            $("#customBackgroudColorpicker").spectrum({
                color: this.customBackgroundColor(),
                hide: function (color) {
                    _this.customBackgroundColor(color.toHexString());
                    $("body").css("background-color", color.toHexString());
                },
                move: function (color) {
                    $("body").css("background-color", color.toHexString());
                }
            });
            $("#customFontColorpicker").spectrum({
                color: this.customFontColor(),
                hide: function (color) {
                    _this.customFontColor(color.toHexString());
                    $("body").css("color", color.toHexString());
                },
                move: function (color) {
                    $("body").css("color", color.toHexString());
                }
            });
        };
        ViewModel.prototype.loadChapter = function (id, lastPage, chapterProgress) {
            var _this = this;
            if (lastPage === void 0) { lastPage = false; }
            if (chapterProgress === void 0) { chapterProgress = null; }
            this.isLoading(true);
            $("#text-container").empty();
            this.currentChapterId(id);
            if (!lastPage) {
                this.page(0);
            }
            try {
                var url = "reader/" + this.workId + "/" + id;
                setTimeout(function () {
                    metrikaUtils_1.default.hit(url);
                    metrikaUtils_1.default.reachGoal("goToReader", { workId: _this.workId });
                }, 100);
                if (this.isInit) {
                    if (history && history.pushState) {
                        history.pushState({ chapterId: id }, "", app.rootUrl + url);
                    }
                }
            }
            catch (ex) {
                try {
                    console.error(ex);
                }
                catch (ex) { }
            }
            var readTextLength = 0;
            var chapters = this.chapters();
            for (var i = 0; i < chapters.length; i++) {
                var c = chapters[i];
                if (c.id === id) {
                    break;
                }
                readTextLength += c.textLength;
            }
            this.readTextLength(readTextLength);
            ajaxUtils_1.AjaxUtils.get("reader/" + this.workId + "/chapter", {
                id: id
            })
                .done(function (result, textStatus, jqXHR) {
                if (!result.isSuccessful) {
                    if (result.messages && result.messages.length) {
                        if (result.messages[0] === "Suspended") {
                            _this.showSuspendedForm(true);
                            _this.isLoading(false);
                            return;
                        }
                        if (result.messages[0] === "Unauthorized") {
                            _this.showUnauthorizedForm(true);
                            _this.isLoading(false);
                            return;
                        }
                        if (result.messages[0] === "Paid") {
                            _this.price = result.data.price;
                            _this.discount = result.data.discount;
                            _this.discountEnd = result.data.discountEnd;
                            _this.showBuyForm(true);
                            _this.isLoading(false);
                            return;
                        }
                        if (result.messages[0] === "Unadulted") {
                            _this.showUnadultedForm(true);
                            _this.isLoading(false);
                            return;
                        }
                        alert(result.messages[0]);
                        return;
                    }
                }
                var secret = jqXHR.getResponseHeader("Reader-Secret");
                var userId = window["app"].userId || "";
                var key = secret.split("").reverse().join("") + "@_@" + userId;
                var text = _.map(result.data.text, function (c, i) {
                    return String.fromCharCode(result.data.text.charCodeAt(i) ^ key.charCodeAt(Math.floor(i % key.length)));
                })
                    .join("");
                var headerText;
                if (_this.workForm === "Story") {
                    headerText = _this.workTitle;
                }
                else {
                    headerText = _this.currentChapter().title;
                }
                if (_this.workForm !== "Story") {
                    document.title = "\u041A\u043D\u0438\u0433\u0430 " + _this.workTitle + ", " + _this.currentChapter().title + ", " + _this.authorName + " \u0447\u0438\u0442\u0430\u0442\u044C \u043E\u043D\u043B\u0430\u0439\u043D";
                }
                else {
                    document.title = _this.workTitle + ", " + _this.authorName + " \u0447\u0438\u0442\u0430\u0442\u044C \u043E\u043D\u043B\u0430\u0439\u043D";
                }
                var header = "<h1>" + headerText + "</h1>";
                if (_this.epilog && !_this.nextChapter()) {
                    text += "<hr /><p style='text-indent: 0'><b>\u041E\u0442 \u0430\u0432\u0442\u043E\u0440\u0430</b></p>" + _this.epilog;
                }
                $("#text-container").html(header + text);
                imageZoomUtils_1.default.init("#text-container");
                setTimeout(function () {
                    if (chapterProgress) {
                        if (_this.readerMode() === "book") {
                            _this.scrollWidth($("#text-container").get(0).scrollWidth);
                            _this.$reader.animate({ scrollTop: 0 }, "fast");
                            if (lastPage) {
                                _this.page(Math.ceil(_this.totalPages() / 2) - 1);
                            }
                            _this.chapterProgressPercent(chapterProgress);
                        }
                        else {
                            var percent = chapterProgress / 100;
                            var height = $("#text-container").height();
                            _this.$reader.animate({ scrollTop: height * percent }, "fast");
                            _this.chapterProgressPercent(percent);
                        }
                    }
                    else {
                        _this.chapterProgressPercent(chapterProgress);
                    }
                    setTimeout(function () { _this.isLoading(false); }, 200);
                    if (app.isAuthenticated) {
                        setTimeout(function () {
                            _this.updateReadingProgress();
                        }, 10000);
                    }
                }, 100);
            });
        };
        ViewModel.prototype.updateReadingProgress = function () {
            var _this = this;
            var data = {
                wId: this.workId,
                cId: this.currentChapterId(),
                wp: this.progressPercent(),
                cp: this.chapterProgressPercent() * 100,
                sId: this.sessionId,
                aa: app.isAuthenticated && (window["AppComponents"].LibraryButton) && window["AppComponents"].LibraryButton.currentState() !== "Reading"
            };
            if (this.readerMode() === "scroll") {
                var height = $("#text-container").height();
                var scrollTop = this.$reader.scrollTop();
                data.cp = scrollTop / height * 100;
            }
            ajaxUtils_1.AjaxUtils.post(app.statsApiUrl + "reader/update-progress?" + $.param(data), null, true)
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                if (result.data && result.data.newLibraryId) {
                    try {
                        metrikaUtils_1.default.reachGoal("addToLibrary", { workId: _this.workId, state: "Reading", inReader: true });
                    }
                    catch (ex) { }
                    toastr.info("<div>Произведение добавлено в вашу библиотеку. <a id='cancelAutoLibrary'>Отменить?</a></div>", "", {
                        timeOut: 15000,
                        tapToDismiss: false
                    });
                    var libraryBtn = window["AppComponents"].LibraryButton;
                    if (libraryBtn) {
                        libraryBtn.currentState("Reading");
                    }
                    $("#cancelAutoLibrary").on("click", function (e) {
                        toastr.clear();
                        ajaxUtils_1.AjaxUtils.post("work/removeFromLibrary", { id: result.data.newLibraryId, cancel: true })
                            .done(function (result) {
                            if (!result.isSuccessful) {
                                alert(result.messages[0]);
                                return;
                            }
                            ;
                            _this.showModal({
                                title: "Изменение настроек",
                                maxWidth: "450px",
                                message: "Произведение удалено из вашей библиотеки.<br/>" +
                                    "Хотите отключить автоматические добавление в библитеку (не рекомендуется)?<br/> " +
                                    "Вы всегда можете поменять эти настройки в Личном кабинете.",
                                type: modalDialog_1.ModalType.ReverseConfirm,
                                onSubmit: function () {
                                    return ajaxUtils_1.AjaxUtils.post("account/disableAutoAddToLibrary", {}).done(function () {
                                        toastr.success("Настройки сохранены.");
                                    });
                                }
                            });
                            if (libraryBtn) {
                                libraryBtn.currentState("None");
                            }
                        });
                    });
                }
            });
            if (app.userId) {
                readingProgressUtils_1.default.updateIfNeeded(app.userId, data.wId, data.cId, data.cp, data.wp, data.sId);
            }
        };
        ViewModel.prototype.nextPage = function () {
            if (this.isDisabled() || this.isLoading() || this.showBuyForm())
                return;
            this.controlsIsVisible(false);
            if (!this.endOfChapter()) {
                var page = this.page();
                this.page(page + 1);
            }
            else {
                var chapters = this.chapters();
                var index = chapters.indexOf(this.currentChapter());
                index++;
                if (index < chapters.length) {
                    this.loadChapter(chapters[index].id);
                }
                else if (this.nextSeriesWorkId) {
                    this.showSeriesNextWork();
                }
            }
        };
        ViewModel.prototype.showSeriesNextWork = function () {
            var _this = this;
            this.showModal({
                title: "Переход к следующей книге",
                maxWidth: "450px",
                message: "Вы дочитали последнюю главу этой книги.<br/>" +
                    "Перейти к следующей книге цикла?<br/> ",
                type: modalDialog_1.ModalType.Confirm,
                onSubmit: function () {
                    location.href = "/reader/" + _this.nextSeriesWorkId;
                }
            });
        };
        ViewModel.prototype.previousPage = function () {
            if (this.isDisabled() || this.isLoading() || this.showBuyForm())
                return;
            this.controlsIsVisible(false);
            var page = this.page();
            if (page > 0) {
                this.page(page - 1);
            }
            else {
                var chapters = this.chapters();
                var index = chapters.indexOf(this.currentChapter());
                index--;
                if (index >= 0) {
                    this.loadChapter(chapters[index].id, true);
                }
            }
        };
        ViewModel.prototype.toggleFontList = function () {
            this.fontListIsOpen(!this.fontListIsOpen());
        };
        ViewModel.prototype.toggleReaderMode = function () {
            this.isLoading(true);
            if (this.readerMode() === "scroll") {
                this.readerMode("book");
            }
            else {
                this.readerMode("scroll");
            }
        };
        ViewModel.prototype.toggleFullScreen = function () {
            if (screenfull.isFullscreen) {
                screenfull.exit();
            }
            else {
                screenfull.request(document.body);
            }
            setTimeout(function () {
                $("#btnFullScreen").blur();
            }, 50);
        };
        ViewModel.prototype.showLeftPanel = function () {
            var _this = this;
            if (this.visibleLeftPanel()) {
                this.hideLeftPanel();
                return;
            }
            this.visibleLeftPanel(true);
            setTimeout(function () {
                _this.$reader.on("click.panel", function () {
                    _this.hideLeftPanel();
                });
            });
        };
        ViewModel.prototype.hideLeftPanel = function () {
            this.visibleLeftPanel(false);
            this.$reader.off("click.panel");
        };
        ViewModel.prototype.contentClick = function () {
            if (this.readerMode() !== "scroll") {
                this.controlsIsVisible(!this.controlsIsVisible());
            }
            return true;
        };
        ViewModel.prototype.onControlsHover = function () {
            this.controlsIsVisible(true);
        };
        ViewModel.prototype.increaseBrightness = function () {
            var brightness = this.brightness() + 1;
            if (brightness <= this.maxBrightness) {
                this.brightness(brightness);
            }
        };
        ViewModel.prototype.decreaseBrightness = function () {
            var brightness = this.brightness() - 1;
            if (brightness >= this.minBrightness) {
                this.brightness(brightness);
            }
        };
        ViewModel.prototype.increaseFontSize = function () {
            var fontSize = this.fontSize() + 1;
            if (fontSize <= this.maxFontSize) {
                this.fontSize(fontSize);
            }
        };
        ViewModel.prototype.decreaseFontSize = function () {
            var fontSize = this.fontSize() - 1;
            if (fontSize >= this.minFontSize) {
                this.fontSize(fontSize);
            }
        };
        ViewModel.prototype.nextFont = function () {
            var fontIndex = this.fontList.indexOf(this.fontFamily());
            fontIndex = fontIndex < this.fontList.length - 1 ? fontIndex + 1 : 0;
            this.fontFamily(this.fontList[fontIndex]);
        };
        ViewModel.prototype.previousFont = function () {
            var fontIndex = this.fontList.indexOf(this.fontFamily());
            fontIndex = fontIndex === 0 ? this.fontList.length - 1 : fontIndex - 1;
            this.fontFamily(this.fontList[fontIndex]);
        };
        ViewModel.prototype.setAdultCookie = function () {
            cookieUtils_1.default.setAdultUser();
            this.goToChapter(this.currentChapter());
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});



},{"../../app/utils/cookieUtils":51,"../../app/utils/readingProgressUtils":66,"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/imageZoomUtils":57,"../utils/localStorageUtils":59,"../utils/metrikaUtils":61,"./base/baseViewModel":92,"jquery":214,"knockout":191,"lodash":216,"screenfull":179,"toastr":199}],145:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel() {
            _super.apply(this, arguments);
            this.code = ko.observable();
        }
        /** Отключает 2FA */
        ViewModel.prototype.removeGA = function () {
            var _this = this;
            this.removeError();
            if (!this.code()) {
                this.showError("Введите код подтверждения двухфакторной аутентификации!");
                return;
            }
            ajaxUtils_1.AjaxUtils.post("account/removeTotp", { code: this.code() })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                if (result.data) {
                    location.href = "/account/security";
                }
                else {
                    _this.showError("Указанный код неверен!");
                }
            });
        };
        ViewModel.prototype.showError = function (message) {
            $("#form-group-code").addClass("has-error");
            $("#form-group-code .error").html(message);
        };
        ViewModel.prototype.removeError = function () {
            $("#form-group-code").removeClass("has-error");
            $("#form-group-code .error").html("");
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191}],146:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "numeral", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isInitialized = false;
            this.groupBy = ko.observable();
            this.itemTitle = ko.pureComputed(function () {
                var groupBy = _this.groupBy();
                if (groupBy === "work") {
                    return "Произведения";
                }
                else if (groupBy === "series") {
                    return "Циклы";
                }
                else if (groupBy === "format") {
                    return "Формат";
                }
                return "";
            });
            this.items = ko.pureComputed(function () {
                var groupBy = _this.groupBy();
                var items;
                if (groupBy === "work") {
                    items = _this.works.slice();
                    items.unshift({ id: "null", title: "Все" });
                }
                else if (groupBy === "series") {
                    items = _this.series.slice();
                    items.unshift({ id: "null", title: "Все" }, { id: "0", title: "Без цикла" });
                }
                else if (groupBy === "format") {
                    items = _this.workFormat.slice();
                    items.unshift({ id: "null", title: "Все" });
                }
                return items;
            });
            this.itemId = ko.observable();
            this.numeral = numeral;
            this.startDate = ko.observable();
            this.endDate = ko.observable();
            this.isLoading = ko.observable(true);
            this.showFullStats = ko.observable();
            this.totalViewCount = ko.observable(0);
            this.uniqueViewCount = ko.observable(0);
            this.commentCount = ko.observable(0);
            this.likeCount = ko.observable(0);
            this.libraryCount = ko.observable(0);
            this.dateRangePickerOptions = {
                ranges: {
                    'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                    'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")],
                    'За прошлый месяц': [moment().startOf("day").add(-30, "days").add(-1, "months"), moment().startOf("day").add(-31, "days")],
                    'За 3 месяца': [moment().startOf("day").add(-30, "days").add(-2, "months"), moment().endOf("day")],
                    'За год': [moment().startOf("day").add(-12, "months"), moment().endOf("day")]
                }
            };
            this.showFullStats(options.showFullStats);
            this.auId = options.auId;
            this.works = options.works;
            this.series = options.series;
            this.workFormat = options.workFormat;
            this.itemId(options.itemId);
            this.startDate(options.startDate ? moment(options.startDate) : moment().startOf("day").add(-6, "days"));
            this.endDate(options.endDate ? moment(options.endDate) : moment().endOf("day"));
            setTimeout(function () { return _this.initComputed(); }, 100);
            this.isInitialized = true;
        }
        ViewModel.prototype.initComputed = function () {
            var _this = this;
            this.filterData = ko.computed(function () {
                var filterData = {
                    startDate: _this.startDate().toISOString(),
                    endDate: _this.endDate().toISOString(),
                    groupBy: _this.groupBy(),
                    itemId: _this.itemId(),
                    auId: _this.auId
                };
                return filterData;
            });
            ko.computed(function () {
                _this.isLoading(true);
                var data = _this.filterData();
                if (_this.isInitialized) {
                    if (_this.showFullStats()) {
                        _this.loadDynamicChart();
                    }
                    else {
                        _this.isLoading(false);
                    }
                }
                try {
                    if (!data.workId || data.workId === "null") {
                        delete data.workId;
                    }
                    if (!data.auId || data.auId === "null") {
                        delete data.auId;
                    }
                    history.replaceState(null, null, "user-activity?" + $.param(data));
                }
                catch (e) {
                }
            });
        };
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/user-activity-data", this.filterData())
                .done(function (result) {
                var daysInPerios = Math.floor((_this.endDate() - _this.startDate()) / (1000 * 60 * 60 * 24));
                var minPeriod = "DD";
                var categoryBalloonDateFormat = "MMMM DD, YYYY";
                if (daysInPerios > 40) {
                    minPeriod = "MM";
                    categoryBalloonDateFormat = "MMMM, YYYY";
                }
                _this.totalViewCount(_.sumBy(result.data, "totalViewCount"));
                _this.uniqueViewCount(_.sumBy(result.data, "uniqueViewCount"));
                _this.commentCount(_.sumBy(result.data, "commentCount"));
                _this.likeCount(_.sumBy(result.data, "likeCount"));
                _this.libraryCount(_.sumBy(result.data, "libraryCount"));
                var viewCountChart = AmCharts.makeChart("viewCountChart", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    valueAxes: [
                        {
                            id: "countAxis",
                            axisAlpha: 0,
                            position: "left",
                            integersOnly: true,
                            title: "Количество"
                        }, {
                            title: "Время чтения, часы",
                            id: "durationAxis",
                            axisAlpha: 0,
                            gridAlpha: 0,
                            position: "right"
                        }
                    ],
                    graphs: [
                        {
                            balloonText: "Просмотров: [[value]]",
                            fillAlphas: 0.7,
                            legendValueText: "[[value]]",
                            title: "Просмотров",
                            type: "column",
                            valueField: "totalViewCount",
                            valueAxis: "countAxis"
                        }, {
                            balloonText: "Читателей: [[value]]",
                            type: "column",
                            clustered: false,
                            fillAlphas: 0.5,
                            columnWidth: 0.5,
                            legendValueText: "[[value]]",
                            title: "Читателей",
                            valueField: "uniqueViewCount",
                            valueAxis: "countAxis",
                            lineColor: "#0D52D1",
                            showBalloon: false
                        }, {
                            balloonText: "Время чтения: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]] ч.",
                            title: "Время чтения",
                            fillAlphas: 0,
                            valueField: "spentTime",
                            lineColor: "#FF9E01",
                            valueAxis: "durationAxis"
                        }
                    ],
                    chartCursor: {
                        categoryBalloonDateFormat: categoryBalloonDateFormat,
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        valueBalloonsEnabled: false,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY",
                    categoryField: "date",
                    categoryAxis: {
                        parseDates: true,
                        dashLength: 1,
                        minorGridEnabled: true,
                        minPeriod: minPeriod
                    },
                    legend: {
                        equalWidths: false,
                        useGraphSettings: true,
                        align: "center"
                    },
                    dataProvider: result.data,
                    pathToImages: window["app"].rootUrl + "dist/vendor/amcharts/images/"
                });
                var secondChart = AmCharts.makeChart("secondChart", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    autoMargins: false,
                    marginLeft: 80,
                    marginRight: 75,
                    valueAxes: [
                        {
                            id: "сount",
                            axisAlpha: 0,
                            position: "left",
                            integersOnly: true
                        }
                    ],
                    graphs: [
                        {
                            balloonText: "Библиотек: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]]",
                            title: "Добавлений в библиотеку",
                            fillAlphas: 0,
                            valueField: "libraryCount",
                            valueAxis: "сount",
                            lineColor: "#37bc9b"
                        },
                        {
                            balloonText: "Комментариев: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]]",
                            title: "Количество комментариев",
                            fillAlphas: 0,
                            valueField: "commentCount",
                            valueAxis: "сount",
                            lineColor: "#7266ba"
                        }, {
                            balloonText: "Количество лайков: [[value]]",
                            type: "smoothedLine",
                            bullet: "square",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]]",
                            title: "Количество лайков",
                            fillAlphas: 0,
                            valueField: "likeCount",
                            valueAxis: "сount",
                            lineColor: "#84b761"
                        }
                    ],
                    chartCursor: {
                        categoryBalloonDateFormat: categoryBalloonDateFormat,
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        valueBalloonsEnabled: false,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY",
                    categoryField: "date",
                    categoryAxis: {
                        parseDates: true,
                        dashLength: 1,
                        minorGridEnabled: true,
                        minPeriod: minPeriod
                    },
                    legend: {
                        equalWidths: false,
                        useGraphSettings: true,
                        align: "center"
                    },
                    dataProvider: result.data,
                    pathToImages: window["app"].rootUrl + "dist/vendor/amcharts/images/"
                });
                // Костыль против глюка SVG в Хроме
                function endsWith(str, suffix) {
                    return str.indexOf(suffix, str.length - suffix.length) !== -1;
                }
                var badPart = "M0,0 L0,0";
                setTimeout(function () {
                    $("svg path").each(function (i, el) {
                        var dAttr = $(el).attr("d");
                        if (endsWith(dAttr, badPart)) {
                            $(el).attr("d", dAttr.substring(0, dAttr.length - badPart.length));
                        }
                    });
                }, 50);
                _this.isLoading(false);
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191,"lodash":216,"moment":219,"numeral":220}],147:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "numeral", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isInitialized = false;
            this.workId = ko.observable();
            this.valueType = ko.observable();
            this.selectedWorkTitle = ko.observable("");
            this.startDate = ko.observable();
            this.endDate = ko.observable();
            this.isLoading = ko.observable(true);
            this.noData = ko.observable(false);
            this.totalViewCount = ko.observable(0);
            this.initComputed = function () {
                _this.workId(_this.options.workId);
                _this.valueType(_this.options.valueType);
                _this.filterData = ko.computed(function () {
                    var filterData = {
                        startDate: _this.startDate().toISOString(),
                        endDate: _this.endDate().toISOString(),
                        workId: _this.workId(),
                        valueType: _this.valueType,
                        auId: _this.auId
                    };
                    return filterData;
                }).extend({ rateLimit: { timeout: 50, method: "notifyWhenChangesStop" } });
                ko.computed(function () {
                    _this.isLoading(true);
                    var data = _this.filterData();
                    console.log(data);
                    if (_this.isInitialized && data.workId) {
                        _this.refreshGrid();
                    }
                    var selectedWork = _.find(_this.allWorks, function (w) { return w.id == data.workId; });
                    _this.selectedWorkTitle(selectedWork ? selectedWork.title : "");
                    try {
                        if (!data.workId || data.workId === "null") {
                            delete data.workId;
                        }
                        if (!data.auId || data.auId === "null") {
                            delete data.auId;
                        }
                        history.replaceState(null, null, "stats?" + $.param(data));
                    }
                    catch (e) {
                    }
                });
            };
            this.auId = options.auId;
            this.allWorks = options.allWorks;
            this.startDate(options.startDate ? moment(options.startDate) : moment().startOf("day").add(-6, "days"));
            this.endDate(options.endDate ? moment(options.endDate) : moment().endOf("day"));
            setTimeout(function () { return _this.initComputed(); }, 100);
            this.isInitialized = true;
            window["numeral"] = numeral;
        }
        ViewModel.prototype.refreshGrid = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/work/stats/data", this.filterData())
                .done(function (result) {
                _this.noData(false);
                var columnNames = [];
                var period = result.data.period;
                var valueType = _this.valueType();
                var rows = _.map(result.data.stats, function (x) {
                    Array.prototype.push.apply(columnNames, _.keys(x.data));
                    return _.extend({
                        id: x.id,
                        title: x.title,
                    }, x.data);
                });
                if (columnNames.length === 0) {
                    _this.noData(true);
                    _this.isLoading(false);
                    return;
                }
                columnNames = _.uniq(columnNames);
                columnNames.sort().reverse();
                var columns = [
                    {
                        field: "title",
                        title: "Часть",
                        width: 200,
                        locked: true,
                    }
                ];
                var momentFormat = period === "month" ? "MMM YYYY" : "DD.MM";
                var colWidth = period === "month" ? 95 : 70;
                var colFormat = "0,0";
                if (valueType !== "hit") {
                    colWidth = 100;
                    colFormat = "00:00:00";
                }
                _.each(columnNames, function (c) {
                    var title = moment(c.replace("c", ""), "YYYYMMDD").format(momentFormat);
                    var colParams = {
                        field: c,
                        title: title,
                        width: colWidth,
                        template: "# if(data." + c + ") { # #= numeral(" + c + ").format('" + colFormat + "') # # } #"
                    };
                    columns.push(colParams);
                });
                var grid = $("#grid").data("kendoGrid");
                if (grid) {
                    grid.destroy();
                }
                $("#grid").empty();
                $("#grid").kendoGrid({
                    dataSource: {
                        data: rows
                    },
                    height: 550,
                    scrollable: true,
                    sortable: true,
                    pageable: false,
                    columns: columns
                });
                _this.isLoading(false);
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191,"lodash":216,"moment":219,"numeral":220}],148:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 100;
            this.categoryId = ko.observable();
            this.text = ko.observable().extend({
                required: true
            });
            this.tags = ko.observableArray(this.options.tags || []).extend({
                maxLength: { params: 5, message: "Нужно указать не более 5-ти тэгов" }
            });
            this.tagsSelect2Settings = {
                placeholder: 'До 5 тэгов через запятую...',
                tags: true, ajax: {
                    url: window["app"].rootUrl + "post/searchTags",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [','],
                maximumSelectionLength: 5,
                language: {
                    maximumSelected: function () { return 'Вы можете выбрать не более 5 тэгов.'; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    item.count = item.count || 0;
                    var markup = "<div class='clearfix'>\
                <div class='pull-left'>" + item.text + "</div>\
                <div class='pull-right'>" + item.count + "<div>\
                </div>";
                    return markup;
                }
            };
            this.id = options.id;
            setTimeout(function () {
                _this.initValidation();
            }, 100);
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
        }
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        ViewModel.prototype.showDeletePostModal = function () {
            var _this = this;
            this.showModal({
                title: "Удаление рецензии",
                message: "Вы точно хотите удалить эту рецензию?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("review/delete", {
                        id: _this.id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.forceRedirectToPage(result.data.redirectUrl);
                        }
                    });
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216}],149:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "./base/baseViewModel", "../utils/richContentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.startDate = ko.observable(moment().startOf("day").add(-6, "days"));
            this.endDate = ko.observable(moment().endOf("day"));
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = "";
            this.dateRangePickerOptions = {
                ranges: {
                    'За сегодня': [moment().startOf("day"), moment().endOf("day")],
                    'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                    'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")]
                }
            };
            this.isLoading = ko.observable(true);
            this.filterData = ko.computed(function () {
                var filterData = {
                    from: moment(_this.startDate()).format("YYYY-MM-DD"),
                    to: moment(_this.endDate()).format("YYYY-MM-DD")
                };
                return filterData;
            });
            if (options.startDate && options.endDate) {
                this.startDate(moment(options.startDate).local().startOf("day"));
                this.endDate(moment(options.endDate).local().endOf("day"));
            }
            richContentUtils_1.default.processHtml(".posts");
            setTimeout(function () {
                _this.filterData.subscribe(function (data) {
                    var filterData = $.param(data);
                    var url = window.location.pathname + "?" + filterData;
                    _this.redirectToPage(url);
                });
            }, 100);
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (_this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                return false;
            });
            richContentUtils_1.default.processHtml("#search-results");
        }
        ViewModel.prototype.clearSearchQuery = function () {
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                $(".search-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/richContentUtils":67,"./base/baseViewModel":92,"jquery":214,"knockout":191,"moment":219}],150:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/baseViewModel", "../utils/richContentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.searchQuery = ko.observable(this.options.query);
            this.searchQueryHasFocus = ko.observable(false);
            this.submitQuery = "";
            this.isClearBtn = false;
            this.showDeleted = ko.observable(false);
            $(document).on("submit.search", "form[data-pjax]", function (event) {
                if (!_this.isClearBtn || _this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                _this.isClearBtn = false;
                return false;
            });
            richContentUtils_1.default.processHtml("#search-results");
            setTimeout(function () {
                _this.showDeleted.subscribe(function () {
                    $(".search-form").submit();
                });
            }, 200);
        }
        ViewModel.prototype.clearSearchQuery = function () {
            var _this = this;
            if (this.searchQuery().length === 0) {
                $(".search-form").removeClass("open");
                return;
            }
            this.searchQuery("");
            setTimeout(function () {
                _this.isClearBtn = true;
                $(".search-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/richContentUtils":67,"./base/baseViewModel":92,"jquery":214,"knockout":191}],151:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/validatedViewModel", "../utils/richContentUtils", "../utils/commentUtils", "../utils/socialUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var richContentUtils_1 = require("../utils/richContentUtils");
    var commentUtils_1 = require("../utils/commentUtils");
    var socialUtils_1 = require("../utils/socialUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.commentSubscription = ko.observable();
            socialUtils_1.default.init();
            commentUtils_1.default.init(options.lastViewTime);
            richContentUtils_1.default.processHtml(".full-post, .comments");
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/commentUtils":49,"../utils/richContentUtils":67,"../utils/socialUtils":68,"./base/validatedViewModel":93,"knockout":191}],152:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "moment", "./base/baseViewModel", "../utils/dateTimeUtils", "../plugins/stickySidebar"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var moment = require("moment");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var stickySidebar_1 = require("../plugins/stickySidebar");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.searchQuery = ko.observable(this.options.query);
            this.tags = ko.observableArray(this.options.tags || []);
            this.postSortOrder = ko.observable();
            this.workTagsSelect2Settings = this.getSelect2Options("work/searchTags");
            this.postTagsSelect2Settings = this.getSelect2Options("post/searchTags");
            this.collectionTagsSelect2Settings = this.getSelect2Options("collection/searchTags");
            this.artTagsSelect2Settings = this.getSelect2Options("art/searchTags");
            this.startDate = ko.observable(moment().startOf("day").add(-6, "days"));
            this.endDate = ko.observable(moment().endOf("day"));
            this.startDateAsString = ko.pureComputed(function () {
                return moment(_this.startDate()).format("YYYY-MM-DD");
            });
            this.endDateAsString = ko.pureComputed(function () {
                return moment(_this.endDate()).format("YYYY-MM-DD");
            });
            this.dateRangePickerOptions = {
                ranges: {
                    'За сегодня': [moment().startOf("day"), moment().endOf("day")],
                    'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                    'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")]
                }
            };
            this.submitQuery = this.options.query;
            this.isClearBtn = false;
            if (options.startDate && options.endDate) {
                this.startDate(moment(options.startDate).local().startOf("day"));
                this.endDate(moment(options.endDate).local().endOf("day"));
            }
            $(document).off("submit", "form[data-pjax]");
            $(document).on("submit", "form[data-pjax]", function (event) {
                if (!_this.isClearBtn || _this.submitQuery !== _this.searchQuery()) {
                    _this.submitQuery = _this.searchQuery();
                    $.pjax.submit(event, "#search-results", { fragment: "#search-results" });
                }
                _this.isClearBtn = false;
                return false;
            });
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime($("#search-results"));
            });
            $(document).ready(function () {
                stickySidebar_1.default.init($("#sticky"));
            });
        }
        ViewModel.prototype.getSelect2Options = function (url) {
            return {
                placeholder: "До 5 тэгов через запятую...",
                ajax: {
                    url: window["app"].rootUrl + url,
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [","],
                maximumSelectionLength: 5,
                language: {
                    maximumSelected: function () { return "Вы можете выбрать не более 5 тэгов."; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    var markup = "<div class='clearfix'>\
                        <div class='pull-left'>" + item.text + "</div>\
                        <div class='pull-right'>" + item.count + "<div>\
                        </div>";
                    return markup;
                }
            };
        };
        ViewModel.prototype.dispose = function () {
            $(document).off("submit", "form[data-pjax]");
        };
        ViewModel.prototype.categoryClick = function (url) {
            $.pjax({ container: "#pjax-container", url: url + "&q=" + this.searchQuery() });
        };
        ViewModel.prototype.clearSearchQuery = function () {
            var _this = this;
            this.searchQuery("");
            setTimeout(function () {
                _this.isClearBtn = true;
                $("#search-query-form").submit();
            });
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../plugins/stickySidebar":43,"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"knockout":191,"lodash":216,"moment":219}],153:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93}],154:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel() {
            _super.apply(this, arguments);
            this.code = ko.observable();
        }
        /** Подключает TOTP */
        ViewModel.prototype.addTotp = function () {
            var _this = this;
            this.removeError();
            if (!this.code()) {
                this.showError("Введите код подтверждения двухфакторной аутентификации!");
                return;
            }
            ajaxUtils_1.AjaxUtils.get("account/addTotp", { code: this.code })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                if (result.data) {
                    location.href = "/account/security";
                }
                else {
                    _this.showError("Указанный код неверен!");
                }
            });
        };
        ViewModel.prototype.copySecretKey = function () {
            var text = $('#secretKey').val();
            var input = document.createElement('input');
            input.setAttribute('value', text.toString());
            document.body.appendChild(input);
            input.select();
            var result = document.execCommand('copy');
            document.body.removeChild(input);
            if (result) {
                this.showModal({
                    title: "\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F",
                    type: 3,
                    message: "Секретный ключ скопирован в буфер обмена"
                });
            }
        };
        ViewModel.prototype.showError = function (message) {
            $("#form-group-code").addClass("has-error");
            $("#form-group-code .error").html(message);
        };
        ViewModel.prototype.removeError = function () {
            $("#form-group-code").removeClass("has-error");
            $("#form-group-code .error").html("");
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191}],155:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            this.processing = ko.observable(false);
            this.rows = ko.observableArray([]);
            this.profileUrl = options.profileUrl;
            if (options.rows) {
                this.rows(options.rows);
            }
        }
        ViewModel.prototype.updateHidden = function (mode, authorId) {
            var _this = this;
            if (this.processing())
                return;
            this.processing(true);
            var data;
            if (mode == "hide") {
                data = { id: authorId };
            }
            else if (mode == "delete") {
                data = { id: authorId, deleted: true };
            }
            else if (mode == "hide-always") {
                data = { id: authorId, isPermanent: true };
            }
            ajaxUtils_1.AjaxUtils.post("hide/author", data).done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                }
                else {
                    _this.updateView(mode, authorId, result.data);
                }
            }).always(function () {
                _this.processing(false);
            });
        };
        ViewModel.prototype.updateView = function (mode, id, data) {
            var row = ko.utils.arrayFirst(this.rows(), function (item) {
                return item.authorId === id;
            });
            if (mode == "delete") {
                this.rows.remove(row);
            }
            else {
                var newRow = JSON.parse(JSON.stringify(row));
                newRow.addedTime = data.addedTime;
                newRow.hidingTimePeriod = data.hidingTimePeriod;
                newRow.hiddenUntil = data.hiddenUntil;
                newRow.hiddenStatus = data.hiddenStatus;
                this.rows.replace(row, newRow);
            }
        };
        ViewModel.prototype.showHiddenStatus = function (status, period) {
            switch (status) {
                case "Hidden":
                    return '<span>Скрыт на ' + period + '</span>';
                case "Permanent":
                    return '<span>Скрыт навсегда</span>';
                case "None":
                    return '<span class="text-success">Не скрыт</span>';
            }
            return '';
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"knockout":191}],156:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "../utils/ajaxUtils", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.ranges = {
                'За неделю': [moment().startOf("day").add(-6, "days"), moment().endOf("day")],
                'За месяц': [moment().startOf("day").add(-30, "days"), moment().endOf("day")]
            };
            this.dateRangePickerOptions = {
                minDate: moment().startOf("day").add(-30, "days"),
                maxDate: moment()
            };
            this.startDate = ko.observable();
            this.endDate = ko.observable();
            this.isLoading = ko.observable(true);
            this.getFilterData = function () {
                return _this.filterData();
            };
            this.type = options.type;
            this.auId = options.auId;
            this.routeName = options.routeName;
            this.chartTitle = options.chartTitle;
            this.startDate(options.startDate ? moment(options.startDate) : moment().startOf("day").add(-6, "days"));
            this.endDate(options.endDate ? moment(options.endDate) : moment().endOf("day"));
            this.filterData = ko.computed(function () {
                var filterData = {
                    startDate: _this.toDateFormat(_this.startDate()),
                    endDate: _this.toDateFormat(_this.endDate()),
                    auId: _this.auId,
                    type: _this.type
                };
                return filterData;
            }).extend({
                rateLimit: {
                    timeout: 300,
                    method: "notifyWhenChangesStop"
                }
            });
            var isInitialized = false;
            setTimeout(function () {
                ko.computed(function () {
                    var data = _this.filterData();
                    if (!isInitialized)
                        return;
                    _this.isLoading(true);
                    _this.loadDynamicChart();
                    var grid = $("#grid").data("kendoGrid");
                    if (grid) {
                        grid.dataSource.read(data);
                    }
                    try {
                        if (!data.auId || data.auId === "null") {
                            delete data.auId;
                        }
                        history.replaceState(null, null, _this.routeName + "?" + $.param(data));
                    }
                    catch (e) {
                    }
                });
            });
            this.filterData.subscribe(function () {
                isInitialized = true;
            });
        }
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/merged-by-day", this.filterData())
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                AmCharts.makeChart("chartdiv", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    synchronizeGrid: true,
                    thousandsSeparator: " ",
                    "categoryField": "date",
                    "categoryAxis": {
                        gridPosition: "start",
                        parseDates: true,
                        dashLength: 1,
                        minPeriod: "DD"
                    },
                    "graphs": [
                        {
                            "title": _this.chartTitle,
                            "valueField": "value",
                            "lineColor": "#80c858",
                            "negativeLineColor": "#a94442",
                            "fillAlphas": 0.4,
                            "type": "smoothedLine"
                        }
                    ],
                    "valueAxes": [
                        {
                            "title": _this.chartTitle
                        }
                    ],
                    "legend": {
                        "useGraphSettings": true
                    },
                    "dataProvider": result.data,
                    chartCursor: {
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY"
                });
                _this.isLoading(false);
            });
        };
        ViewModel.prototype.toDateFormat = function (date) {
            return date.toISOString();
        };
        ViewModel.prototype.toNumberFormat = function (value) {
            return (Math.round(value * 100) / 100).toLocaleString('ru');
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"jquery":214,"knockout":191,"moment":219}],157:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "knockout", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var AccountWalletViewModel = (function (_super) {
        __extends(AccountWalletViewModel, _super);
        function AccountWalletViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.saveCard = ko.observable(false);
            this.savedCardId = ko.observable(-1);
            this.profileId = ko.observable(-1);
            this.giftsEnabled = ko.observable(false);
            this.saveCard(options.saveCard);
            this.giftsEnabled(options.giftsEnabled);
            setTimeout(function () {
                _this.initValidation();
            }, 0);
        }
        AccountWalletViewModel.prototype.onSubmitSucess = function (result) {
            this.reloadPage();
        };
        AccountWalletViewModel.prototype.onSubmitFail = function (result) {
            if (result.messages && result.messages.length > 0)
                toastr.error(result.messages[0]);
        };
        AccountWalletViewModel.prototype.deleteSavedCard = function (all) {
            var _this = this;
            var confirmMessage = all ? "Вы уверены, что хотите отвязать все карты?" : "Вы уверены, что хотите отвязать карту?";
            if (!confirm(confirmMessage))
                return;
            var id = this.savedCardId();
            var auId = this.profileId();
            ajaxUtils_1.AjaxUtils.post("merchant/deleteSavedCard", {
                id: id,
                auId: auId,
                all: all
            })
                .done(function (result) {
                if (result.isSuccessful) {
                    toastr.success('Карта успешно отвязана!');
                    _this.reloadPage();
                }
                else {
                    toastr.error(result.messages[0]);
                }
            });
        };
        return AccountWalletViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = AccountWalletViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"knockout":191,"toastr":199}],158:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.genres = ko.observableArray();
            this.exceptGenreIds = ko.observableArray();
            this.form = ko.observable();
            this.state = ko.observable();
            this.series = ko.observable();
            this.access = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.viewMode = ko.observable();
            this.contestId = ko.observable();
            this.hideFinished = ko.observable(false);
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var genres = _this.genres(), exceptGenreIds = _this.exceptGenreIds(), form = _this.form(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), access = _this.access(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), cntst = _this.contestId(), view = _this.viewMode(), fnd = _this.hideFinished();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                else if (options.rp !== "today") {
                    params.rp = options.rp;
                }
                if (format !== "any") {
                    params.format = format;
                }
                if (form !== "any") {
                    params.form = form;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (access !== "any") {
                    params.access = access;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (duration !== "any" && format == "audiobook") {
                    params.duration = duration;
                }
                if (length !== "any" && format == "ebook") {
                    params.length = length;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                if (cntst) {
                    params.cntst = cntst;
                }
                params.fnd = fnd;
                var genreCodes;
                if (genres && genres.length > 0) {
                    genreCodes = genres.join("&");
                }
                else {
                    genreCodes = "all";
                }
                var url = app.rootUrl + ("work/biblio-night/" + genreCodes + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],159:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.genres = ko.observableArray();
            this.exceptGenreIds = ko.observableArray();
            this.form = ko.observable();
            this.state = ko.observable();
            this.series = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.viewMode = ko.observable();
            this.hideFinished = ko.observable(false);
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var genres = _this.genres(), exceptGenreIds = _this.exceptGenreIds(), form = _this.form(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), view = _this.viewMode(), fnd = _this.hideFinished();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                else if (options.rp !== "today") {
                    params.rp = options.rp;
                }
                if (form !== "any") {
                    params.form = form;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (format !== "any") {
                    params.format = format;
                }
                if (duration !== "any" && format == "audiobook") {
                    params.duration = duration;
                }
                if (length !== "any" && format == "ebook") {
                    params.length = length;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                params.fnd = fnd;
                var genreCodes;
                if (genres && genres.length > 0) {
                    genreCodes = genres.join("&");
                }
                else {
                    genreCodes = "all";
                }
                var url = app.rootUrl + ("work/discounts/" + genreCodes + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],160:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/imageUtils", "../components/modalDialog", "../utils/windowUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    // @ts-ignore
    var ko = require("knockout");
    var _ = require("lodash");
    // @ts-ignore
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var imageUtils_1 = require("../utils/imageUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var windowUtils_1 = require("../utils/windowUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 150;
            this.annotationMaxLength = 1000;
            this.authorNotesMaxLength = 1000;
            this.unsupportedCoverType = ["image/gif", "image/tiff"];
            this.isDirty = false;
            this.uploadErrorMessages = ko.observableArray();
            this.title = ko.observable().extend({
                required: true,
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                return title.length + "/" + _this.titleMaxLength;
            });
            this.coAuthorId = ko.observable();
            this.secondCoAuthorId = ko.observable().extend({
                validation: {
                    validator: function (val) {
                        return val === undefined || val === null || _this.coAuthorId() !== val;
                    },
                    message: "Первый и второй соавторы не могут совпадать."
                }
            });
            this.reciter = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.format() === "Audiobook";
                    }
                },
                maxLength: this.titleMaxLength
            });
            this.linkedWorkId = ko.observable();
            this.workIdSearchSelect2Settings = {
                minimumResultsForSearch: 3,
                placeholder: "Не выбрано",
                allowClear: true,
                ajax: {
                    url: window["app"].rootUrl + "work/searchLinkedWorks",
                    dataType: "json",
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            format: "EBook",
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.id,
                                    text: x.title,
                                    coverUrl: x.coverUrl
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    var markup = "<div class='work'>" + (item.coverUrl ? "<img src='" + item.coverUrl + "' class='work-cover'/>" : "") + "<span>" + item.text + "</span></div>";
                    return markup;
                }
            };
            this.originalAuthor = ko.observable().extend({
                required: {
                    onlyIf: function () {
                        return _this.workForm() === "Translation";
                    }
                },
                maxLength: this.titleMaxLength
            });
            this.translator = ko.observable().extend({
                maxLength: this.titleMaxLength
            });
            this.coAuthorIdSelect2Settings = {
                placeholder: 'Нет соавтора',
                minimumInputLength: 3,
                minimumResultsForSearch: -1,
                allowClear: true,
                ajax: {
                    url: window["app"].rootUrl + "account/searchUser",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            userId: _this.options.authorId,
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.userId,
                                    text: x.fio + " @" + x.userName
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                }
            };
            this.originalAuthorSelect2Settings = {
                placeholder: "Автор оригинала (просмотр статистики)",
                minimumResultsForSearch: 5,
                allowClear: true,
                ajax: {
                    url: window["app"].rootUrl + "account/searchUser",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            userId: _this.options.authorId,
                            q: params.term,
                            page: params.page,
                            onlyFriends: false
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.userId,
                                    text: x.fio + " @" + x.userName
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                }
            };
            this.annotation = ko.observable().extend({
                maxLength: this.annotationMaxLength
            });
            this.annotationHint = ko.pureComputed(function () {
                var annotation = _this.annotation() || "";
                return annotation.length + "/" + _this.annotationMaxLength;
            });
            this.authorNotes = ko.observable().extend({
                maxLength: this.authorNotesMaxLength
            });
            this.authorNotesHint = ko.pureComputed(function () {
                var authorNotes = _this.authorNotes() || "";
                return authorNotes.length + "/" + _this.authorNotesMaxLength;
            });
            this.coverUrl = ko.observable();
            this.coverHeight = ko.observable();
            this.coverWidth = ko.observable();
            this.format = ko.observable();
            this.workForm = ko.observable();
            this.genreId = ko.observable().extend({
                validation: {
                    validator: function (val) {
                        return val !== "null";
                    },
                    message: "Пожалуйста, укажите жанр произведения"
                }
            });
            this.firstSubGenreId = ko.observable();
            this.secondSubGenreId = ko.observable();
            this.tags = ko.observableArray(this.options.tags || []).extend({
                maxLength: { params: 12, message: "Нужно указать не более 12-ти тэгов" }
            });
            this.tagsSelect2Settings = {
                placeholder: 'До 12 тэгов через запятую, разрешены пробелы',
                tags: true,
                ajax: {
                    url: window["app"].rootUrl + "work/searchTags",
                    dataType: "json",
                    tokenSeparators: [","],
                    delay: 300,
                    data: function (params) {
                        return {
                            q: params.term,
                            page: params.page
                        };
                    },
                    processResults: function (result, params) {
                        if (result.isSuccessful) {
                            var data = result.data;
                            data.results = _.map(data.results, function (x) {
                                return {
                                    id: x.title,
                                    text: x.title,
                                    count: x.count || 0
                                };
                            });
                            return data;
                        }
                        return {
                            results: []
                        };
                    }
                },
                tokenSeparators: [','],
                maximumSelectionLength: 12,
                language: {
                    maximumSelected: function () { return 'Вы можете выбрать не более 12-ти тэгов.'; }
                },
                escapeMarkup: function (markup) { return markup; },
                templateResult: function (item) {
                    if (item.loading) {
                        return item.text;
                    }
                    item.count = item.count || 0;
                    return "<div class='clearfix'>\
                <div class='pull-left'>" + item.text + "</div>\
                <div class='pull-right'>" + item.count + "<div>\
                </div>";
                }
            };
            this.adultOnly = ko.observable();
            this.adultOnlyEnabled = ko.observable(true);
            this.privacyDisplayId = ko.observable();
            this.privacyDisplayOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" }
            ];
            this.privacyDownloadsId = ko.observable();
            this.privacyDownloadsOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Мои подписчики и друзья" },
                { id: 3, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.privacyCommentsId = ko.observable();
            this.privacyCommentsOptions = [
                { id: 1, title: "Все" },
                { id: 2, title: "Только друзья" },
                { id: 0, title: "Никто" }
            ];
            this.shadowBanPenalty = ko.observable();
            this.isShadowBan = ko.observable(false);
            this.translationRights = ko.observable();
            this.translationOriginalInfo = ko.observable().extend({
                maxLength: this.authorNotesMaxLength
            });
            this.format(options.format);
            this.workForm(options.workForm);
            this.titleInit = options.titleInit;
            this.annotationInit = options.annotationInit || "";
            this.authorNotesInit = options.authorNotesInit || "";
            this.workForm.subscribe(function (form) {
                if (form === "Poetry") {
                    setTimeout(function () {
                        _this.genreId("13");
                    }, 0);
                }
            });
            this.adultGenreIds = options.adultGenreIds;
            ko.computed(function () {
                var genreId = _this.genreId();
                var subGenreId = _this.firstSubGenreId();
                var secondSubGenreId = _this.secondSubGenreId();
                var isAdultOnly = genreId && _this.adultGenreIds.includes(parseInt(genreId.toString()))
                    || subGenreId && _this.adultGenreIds.includes(parseInt(subGenreId.toString()))
                    || secondSubGenreId && _this.adultGenreIds.includes(parseInt(secondSubGenreId.toString()));
                if (isAdultOnly) {
                    _this.adultOnly(true);
                }
                setTimeout(function () {
                    _this.adultOnlyEnabled(!isAdultOnly);
                }, 50);
            });
            ko.computed(function () {
                var description = _this.title() || "";
                var annotation = _this.annotation() || "";
                var authorNotes = _this.authorNotes() || "";
                var isDirty = stringUtils_1.default.compareWithoutLineBreaks(description, _this.titleInit)
                    || stringUtils_1.default.compareWithoutLineBreaks(annotation, _this.annotationInit)
                    || stringUtils_1.default.compareWithoutLineBreaks(authorNotes, _this.authorNotesInit);
                _this.isDirty = isDirty;
                windowUtils_1.default.setDirty(isDirty);
            });
            this.privacyDisplayId(options.privacyDisplayId);
            this.privacyDownloadsId(options.privacyDownloadsId);
            this.privacyCommentsId(options.privacyCommentsId);
            setTimeout(function () {
                if (options.genreId) {
                    _this.genreId(options.genreId);
                }
                _this.genreId.isModified(false);
                _this.initValidation();
            }, 0);
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
        }
        ViewModel.prototype.showUploadCoverModal = function (CoverChangeDisabled) {
            var _this = this;
            if (CoverChangeDisabled === void 0) { CoverChangeDisabled = false; }
            if (CoverChangeDisabled) {
                this.showModal({
                    title: "\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u043E\u0431\u043B\u043E\u0436\u043A\u0438 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E",
                    type: modalDialog_1.ModalType.Alert,
                    message: "\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043B \u0441\u043C\u0435\u043D\u0443 \u043E\u0431\u043B\u043E\u0436\u043A\u0438 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F."
                });
            }
            else {
                this.showModal({
                    title: "Загрузка изображения",
                    type: modalDialog_1.ModalType.Custom,
                    templateId: "uploadCover",
                    onShow: function ($modal) {
                        _this.uploadErrorMessages([]);
                        var $dropZone = $modal.find((".drop-zone"));
                        imageUtils_1.default.createDropZone($dropZone, function (files) {
                            _this.processFiles(files);
                        });
                    }
                });
            }
        };
        ViewModel.prototype.selectImage = function () {
            var $input = this.modal.getModal().find("input[type='file']");
            $input.click();
        };
        ViewModel.prototype.onSelectImage = function (data, event) {
            this.uploadErrorMessages([]);
            var $input = $(event.target), files = event.target.files;
            this.processFiles(files);
            $input.val("");
        };
        ViewModel.prototype.processFiles = function (files) {
            var _this = this;
            if (files && files.length) {
                var file_1 = files[0];
                var errorMessages = [];
                if (file_1.size > 15 * 1024 * 1024) {
                    errorMessages.push("Слишком большой размер файла. Пожалуйста, выберите файл размером не более 15 мб.");
                }
                if (!/^image\/\w+$/.test(file_1.type) || this.unsupportedCoverType.indexOf(file_1.type) > -1) {
                    errorMessages.push("Данный формат файла не поддерживается. Пожалуйста, выберите изображение.");
                }
                if (errorMessages.length) {
                    this.uploadErrorMessages(errorMessages);
                    return;
                }
                var blobUrl_1 = URL.createObjectURL(file_1);
                imageUtils_1.default.getImageSize(blobUrl_1).done(function (imageSize) {
                    if (imageSize.width < 200 || imageSize.height < 285) {
                        _this.uploadErrorMessages(["Слишком маленький размер изображения."]);
                        return;
                    }
                    _this.coverUrl(blobUrl_1);
                    _this.coverUrlFile = file_1;
                    _this.modal.hide();
                });
            }
        };
        ViewModel.prototype.removeCover = function () {
            URL.revokeObjectURL(this.coverUrl());
            this.coverUrl(null);
            this.coverUrlFile = null;
        };
        ViewModel.prototype.beforeSubmit = function (formElement, extendedData, callback) {
            var _this = this;
            this.errorMessages([]);
            this.processing(true);
            if (this.coverUrlFile) {
                var formData = new FormData();
                formData.append("file", this.coverUrlFile);
                ajaxUtils_1.AjaxUtils.uploadFile("file/uploadCoverImage", formData)
                    .done(function (result) {
                    if (!result.isSuccessful) {
                        _this.errorMessages(result.messages);
                    }
                    else {
                        _this.coverUrl(result.data.url);
                        _this.coverHeight(result.data.height);
                        _this.coverWidth(result.data.width);
                        setTimeout(callback, 50);
                    }
                }).fail(function () {
                    _this.errorMessages(["Произошла ошибка во время выполнения запроса. Попробуйте еще раз через некоторое время."]);
                    _this.processing(false);
                });
            }
            else {
                callback();
            }
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            if (result.data && result.data.redirectUrl) {
                this.redirectToPage(result.data.redirectUrl);
            }
            else {
                this.reloadPage();
            }
        };
        ViewModel.prototype.deleteCoAuthor = function (coAuthorId) {
            var _this = this;
            if (this.processing())
                return;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            this.showModal({
                title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0441\u043E\u0430\u0432\u0442\u043E\u0440\u0430",
                type: 1,
                okBtnText: "Продолжить",
                maxWidth: "500px",
                message: "\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0430\u0432\u0442\u043E\u0440\u0430?" + (this.isDirty ? "<br>Несохраненные изменения будут утеряны." : ""),
                onSubmit: function () {
                    _this.processing(true);
                    windowUtils_1.default.setDirty(false);
                    ajaxUtils_1.AjaxUtils.post("work/deleteCoAuthor", {
                        id: _this.options.id,
                        coAuthorId: coAuthorId
                    })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            toastr.error(result.messages[0]);
                        }
                        else {
                            if (result.messages && result.messages.length > 0) {
                                toastr.success(result.messages[0]);
                            }
                            _this.onSubmitSucess(result);
                        }
                    })
                        .always(function () {
                        setTimeout(function () {
                            _this.processing(false);
                        }, 0);
                    });
                    _this.modal.hide();
                }
            });
        };
        /**
         * Смена основного автора
         * @param coAuthorId - идентификатор соавтора, который становится основным автором
         */
        ViewModel.prototype.changeAuthor = function (coAuthorId) {
            var _this = this;
            if (this.processing())
                return;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            this.showModal({
                title: "\u0421\u043C\u0435\u043D\u0430 \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0433\u043E \u0430\u0432\u0442\u043E\u0440\u0430",
                type: 2,
                okBtnText: "Продолжить",
                maxWidth: "500px",
                message: "\u0412\u044B \u0443\u0432\u0435\u0440\u0435\u043D\u044B \u0447\u0442\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0441\u043C\u0435\u043D\u0438\u0442\u044C \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0433\u043E \u0430\u0432\u0442\u043E\u0440\u0430?" + (this.isDirty ? "<br>Несохраненные изменения будут утеряны." : ""),
                onSubmit: function () {
                    _this.processing(true);
                    windowUtils_1.default.setDirty(false);
                    ajaxUtils_1.AjaxUtils.post("work/change-author", {
                        id: _this.options.id,
                        coAuthorId: coAuthorId
                    })
                        .done(function (result) {
                        if (!result.isSuccessful) {
                            toastr.error(result.messages[0]);
                        }
                        else {
                            if (result.messages && result.messages.length > 0) {
                                toastr.success(result.messages[0]);
                            }
                            _this.onSubmitSucess(result);
                        }
                    })
                        .always(function () {
                        setTimeout(function () {
                            _this.processing(false);
                        }, 0);
                    });
                    _this.modal.hide();
                }
            });
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/imageUtils":56,"../utils/stringUtils":69,"../utils/windowUtils":72,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"lodash":216,"toastr":199}],161:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 200;
            this.title = ko.observable().extend({
                required: true,
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                var characters = title.length;
                return characters + "/" + _this.titleMaxLength;
            });
            this.text = ko.observable();
            this.autoPublish = ko.observable();
            this.autoPublishTime = ko.observable();
            this.autoPublishTimeValue = ko.computed(function () {
                return moment(_this.autoPublishTime()).toISOString();
            });
            this.timePickerIncrement = 15;
            this.dateRangePickerOptions = {
                timePicker: true,
                timePickerIncrement: this.timePickerIncrement,
                timePicker24Hour: true,
                drops: "up",
                minDate: this.getMinDate(),
                locale: { format: "DD MMMM YYYY в HH:mm" }
            };
            this.saveBtnText = ko.pureComputed(function () {
                var autoPublish = _this.autoPublish();
                return autoPublish ? "Запланировать публикацию" : "Опубликовать";
            });
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            var froalaOptions = {
                heightMin: 400,
                heightMax: 500,
                charCounterMax: 200000,
                imageEditButtons: ["imageReplace", "imageAlign", "imageDisplay", "imageAlt", "|", "imageRemove"],
                paragraphStyles: {
                    'fr-indent': "С красной строкой"
                },
                htmlAllowedTags: [
                    "b", "blockquote", "br",
                    "cite", "del", "div", "em", "hr", "i", "img", "li",
                    "ol", "p", "pre", "small", "span", "strike",
                    "strong", "sub", "sup", "table", "dd", "u", "ul", "sup", "sub"
                ],
                toolbarButtons: [
                    "bold", "italic", "underline", "strikeThrough", "|", "typograf",
                    "align", "color", "quote", "insertImage", "|", "clearFormatting", "fullscreen", "html", "|", "undo",
                    "redo"
                ],
                toolbarButtonsMD: [
                    "bold", "italic", "underline", "strikeThrough", "|", "typograf",
                    "align", "color", "quote", "insertImage", "|", "clearFormatting", "fullscreen", "html", "|", "undo",
                    "redo"
                ],
                toolbarButtonsSM: [
                    "bold", "italic", "underline", "strikeThrough", "|", "typograf",
                    "align", "color", "quote", "insertImage", "|", "clearFormatting", "fullscreen", "html", "|", "undo",
                    "redo"
                ],
                toolbarButtonsXS: [
                    "bold", "italic", "underline", "strikeThrough", "|", "typograf",
                    "align", "color", "quote", "insertImage", "|", "clearFormatting", "fullscreen", "html", "|", "undo",
                    "redo"
                ],
                dirtyWhenUpdate: true
            };
            if (options.redLine === false) {
                froalaOptions.toolbarButtons.splice(5, 0, "paragraphStyle");
                froalaOptions.toolbarButtonsMD.splice(5, 0, "paragraphStyle");
                froalaOptions.toolbarButtonsSM.splice(5, 0, "paragraphStyle");
            }
            if (options.autoPublishTime) {
                this.autoPublishTime(moment(options.autoPublishTime).toDate());
                this.autoPublish(true);
            }
            else {
                this.autoPublishTime(this.getMinDate());
            }
            this.froalaOptions = froalaOptions;
            this.errorMessages.subscribe(function (newValue) {
                if (newValue && newValue.length) {
                    $("html, body").stop().animate({ scrollTop: 0 }, "fast");
                }
            });
        }
        ViewModel.prototype.getMinDate = function () {
            var now = moment();
            var minutes = this.timePickerIncrement - now.minutes() % this.timePickerIncrement;
            return now.add("m", minutes).set("s", 0).toDate();
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.redirectToPage(result.data.redirectUrl);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/validatedViewModel":93,"jquery":214,"knockout":191,"moment":219}],162:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "sortable", "../utils/ajaxUtils", "./base/validatedViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var Sortable = require("sortable");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.workId = this.options.workId;
            this.allowDelete = this.options.allowDelete;
            this.enableSorting = ko.observable();
            this.processingChapter = ko.observable(false);
            var ul = $(".sortable")[0];
            if (ul) {
                var sortable = new Sortable(ul, {
                    animation: 150,
                    handle: ".sortable-handle",
                    filter: ".btn",
                    onFilter: function (evt) {
                        var item = evt.item, $ctrl = $(evt.target);
                        $ctrl.trigger(evt);
                    },
                    onEnd: function (e) {
                        ajaxUtils_1.AjaxUtils.post("work/reorderChapter", {
                            workId: _this.workId,
                            oldIndex: e.oldIndex,
                            newIndex: e.newIndex
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                toastr.success("Порядок частей был изменен.");
                            }
                            else {
                                toastr.error(result.messages[0]);
                            }
                        });
                    }
                });
            }
        }
        ViewModel.prototype.updateState = function (state) {
            var _this = this;
            var message = "Потдвердите изменение статуса";
            switch (state) {
                case "InProgress":
                    if (this.options.finished) {
                        message = "Вы точно хотите отменить статус \"завершено\" у произведения?";
                    }
                    else {
                        message = "<b>Важно!</b> Если вы не собираетесь выкладывать книгу на Author.Today целиком, не меняйте данный статус. " +
                            "В случае поступления жалобы от читателя на неверный статус ваш аккаунт может быть заблокирован.";
                    }
                    break;
                case "Finished":
                    message = "Присваивая статус \"завершено\" вы подтверждаете, что <b>весь текст</b> произведения " +
                        "<b>опубликован на сайте</b> и <b>целиком доступен</b> читателю." +
                        " В противном случае выберите статус ознакомительного фрагмента.<br/>" +
                        "В случае поступления жалобы от читателя на неверный статус ваш аккаунт может быть заблокирован.";
                    break;
                case "PromoFragment":
                    message = "Выберите этот статус, если не собираетесь выкладывать книгу на Author.Today целиком.";
                    break;
            }
            this.showModal({
                title: "\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u0430",
                type: 2,
                okBtnText: "Продолжить",
                maxWidth: "500px",
                message: message,
                onSubmit: function () {
                    _this.processing(true);
                    return ajaxUtils_1.AjaxUtils.post("work/updateState", {
                        id: _this.workId,
                        state: state
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.modal.hide();
                            _this.reloadPage();
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    }).always(function () {
                        _this.processing(false);
                    });
                }
            });
        };
        ViewModel.prototype.publish = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/publish", {
                id: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.updateChapterState = function (chapterId, isDraft, autoPublishTime) {
            var _this = this;
            var updateState = function () {
                _this.processingChapter(true);
                ajaxUtils_1.AjaxUtils.post("work/updateChapterState", {
                    workId: _this.workId,
                    chapterId: chapterId,
                    isDraft: isDraft
                }).done(function (result) {
                    _this.processingChapter(false);
                    if (result.isSuccessful) {
                        _this.reloadPage();
                    }
                    else {
                        _this.errorMessages(result.messages);
                    }
                });
            };
            if (autoPublishTime) {
                this.showModal({
                    title: "\u041F\u0443\u0431\u043B\u0438\u043A\u0430\u0446\u0438\u044F \u0447\u0430\u0441\u0442\u0438 \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F",
                    type: 2,
                    okBtnText: "Продолжить",
                    maxWidth: "500px",
                    message: "Вы уверены что хотите опубликовать главу прямо сейчас?",
                    onSubmit: function () {
                        updateState();
                        _this.modal.hide();
                    }
                });
            }
            else {
                updateState();
            }
        };
        ViewModel.prototype.refreshWorkFiles = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.post("work/refreshWorkFiles", {
                workId: this.workId
            }).done(function (result) {
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.showMoveToDraftModal = function () {
            var _this = this;
            this.showModal({
                title: "\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435",
                type: 2,
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0435 \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A?",
                onSubmit: function () {
                    _this.processing(true);
                    return ajaxUtils_1.AjaxUtils.post("work/moveToDraft", {
                        id: _this.workId
                    }).done(function (result) {
                        _this.processing(false);
                        if (result.isSuccessful) {
                            _this.reloadPage();
                        }
                        else {
                            _this.errorMessages(result.messages);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.showDeleteChapterModal = function (id, title) {
            var _this = this;
            this.showModal({
                title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0447\u0430\u0441\u0442\u0438",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u00AB" + title + "\u00BB?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("work/deleteChapter", {
                        id: id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            var $el = $("#chapter_" + id);
                            $el.hide({
                                done: function () {
                                    $el.fadeOut();
                                }
                            });
                            toastr.success("\u00AB" + title + "\u00BB \u0431\u044B\u043B\u0430 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D\u0430.");
                            if (result.data && result.data.withReloadPage) {
                                _this.reloadPage();
                            }
                        }
                    });
                }
            });
        };
        ViewModel.prototype.showDeleteWorkModal = function () {
            var _this = this;
            if (!this.allowDelete) {
                this.showModal({
                    title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E",
                    type: 5,
                    maxWidth: "500px",
                    message: "Вы не можете удалить произведение, т.к. доступ к нему оплатил как минимум один человек.<br/>" +
                        "Чтобы скрыть его из общего доступа, уберите  в черновики."
                });
                return;
            }
            this.showModal({
                title: "Удаление произведения",
                message: "Вы точно хотите удалить произведение?",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("work/delete", {
                        id: _this.workId
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            _this.redirectToPage(result.data.redirectUrl);
                        }
                        else {
                            _this.modal.hide();
                            _this.showModal({
                                title: "Удаление произведения",
                                message: result.messages[0],
                                type: 5
                            });
                        }
                    });
                }
            });
        };
        ViewModel.prototype.requestTranslationReview = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/request-translation-review", {
                id: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.updateTranslationTransStatus = function (status) {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/update-translation-status", {
                id: this.workId,
                status: status
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    _this.errorMessages(result.messages);
                }
            });
        };
        ViewModel.prototype.approveTranslation = function () {
            this.updateTranslationTransStatus('Approved');
        };
        ViewModel.prototype.rejectTranslation = function () {
            this.updateTranslationTransStatus('Rejected');
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"sortable":196,"toastr":199}],163:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "../utils/ajaxUtils", "../utils/stringUtils", "./base/validatedViewModel", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var modalDialog_1 = require("../components/modalDialog");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.price = ko.observable().extend({
                min: {
                    params: 49,
                    message: "Минимальная цена - 49 ₽"
                },
                max: {
                    params: 500,
                    message: "Максимальная цена - 500 ₽"
                }
            });
            this.commission = ko.observable();
            this.totalChapterCount = this.options.totalChapterCount;
            this.exclusiveScanCopies = ko.observableArray([]);
            this.sendExclusiveRequest = function () {
                ajaxUtils_1.AjaxUtils.post("work/" + _this.options.workId + "/exclusive-request", {})
                    .done(function (result) {
                    if (result.isSuccessful) {
                        _this.showModal({
                            title: "Заявка успешно отправлена",
                            type: modalDialog_1.ModalType.Success,
                            message: "Ваша заявка будет рассмотрена в ближайшее время. Иногда это может занимать 2-3 рабочих дня.",
                            maxWidth: "435px"
                        });
                        $("#sendExclusiveRequestBtn").hide();
                    }
                    else {
                        _this.errorMessages(result.messages);
                    }
                }).always(function () {
                    _this.processing(false);
                });
            };
            this.removeScanCopy = function (data) {
                _this.showModal({
                    title: "Удаление изображения",
                    message: "Вы уверены, что хотите изображение?",
                    maxWidth: "400px",
                    type: modalDialog_1.ModalType.ConfirmDelete,
                    okBtnText: "Удалить",
                    onSubmit: function () {
                        _this.processing(true);
                        ajaxUtils_1.AjaxUtils.post("work/delete-exclusive-agreement-scan", { scanCopyId: data.id })
                            .done(function (result) {
                            _this.modal.hide();
                            _this.exclusiveScanCopies.remove(data);
                        }).always(function () {
                            _this.processing(false);
                        });
                    }
                });
            };
            this.sendExclusiveAgreement = function () {
                _this.showModal({
                    title: "Отправка скан-копии",
                    message: "Проверьте, пожалуйста, что вы загрузили скан-копии или фото <b>обеих</b> страниц доп. соглашения и, если всё в порядке, нажмите \"Отправить\"",
                    maxWidth: "400px",
                    type: modalDialog_1.ModalType.Confirm,
                    okBtnText: "Отправить",
                    onSubmit: function () {
                        ajaxUtils_1.AjaxUtils.post("work/send-exclusive-agreement", { id: _this.options.workId })
                            .done(function (result) {
                            if (result.isSuccessful) {
                                _this.showModal({
                                    title: "Заявка успешно отправлена",
                                    type: modalDialog_1.ModalType.Success,
                                    message: "Спасибо! Коммерческий отдел уже получил уведомление и в ближайшее время обработает заявку.<br/>" +
                                        "Если вы загрузили не тот файл - его можно загрузить ещё раз.",
                                    maxWidth: "435px",
                                    onHide: function () {
                                        _this.fullReloadPage();
                                    }
                                });
                                $("#sendExclusiveAgreementBtn").hide();
                            }
                            else {
                                _this.errorMessages(result.messages);
                            }
                        }).always(function () {
                            _this.processing(false);
                        });
                    }
                });
            };
            this.updateCommission = function () {
                _this.showModal({
                    title: "Комиссия",
                    message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u0438\u0441\u0441\u0438\u044E \u043D\u0430 <b>" + _this.commission() + "%</b>?",
                    maxWidth: "400px",
                    type: modalDialog_1.ModalType.Confirm,
                    onSubmit: function () {
                        ajaxUtils_1.AjaxUtils.post("work/updateCommission", {
                            id: _this.options.workId,
                            commission: _this.commission()
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                toastr.success(result.messages[0]);
                            }
                            else {
                                toastr.error(result.messages[0]);
                            }
                            _this.modal.hide();
                        });
                    }
                });
            };
            this.finished = options.finished === true;
            this.freeChapterCount = ko.observable()
                .extend({
                number: true,
                min: {
                    params: 1,
                    onlyIf: function () { return _this.price() > 0; }
                },
                max: {
                    message: options.totalChapterCount === 0
                        ? "Необходимо опубликовать хотя бы одну часть."
                        : "\u0412 \u0432\u0430\u0448\u0435\u043C \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0438 \u0432\u0441\u0435\u0433\u043E " + options.totalChapterCount + " \n                    " + stringUtils_1.default.pluralize(options.totalChapterCount, ["опубликованная часть", "опубликованные части", "опубликованных частей"]) + ".",
                    params: options.totalChapterCount,
                    onlyIf: function () { return _this.price() > 0; }
                }
            });
            setTimeout(function () {
                _this.initValidation();
                _this.price.isModified(false);
            }, 0);
            this.errorMessages.subscribe(function (errors) {
                if (_this.modal && _this.modal.errorMessages) {
                    _this.modal.errorMessages(errors);
                }
            });
            this.exclusiveScanCopies(options.exclusiveScanCopies || []);
            var endpoint = window["app"].rootUrl + "work/" + this.options.workId + "/upload-exclusive-agreement";
            $(function () {
                if (!window["qq"])
                    return;
                var uploader = new qq.FineUploader({
                    multiple: false,
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: endpoint,
                        customHeaders: ajaxUtils_1.AjaxUtils.getHeaders()
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — {sizeLimit}.",
                        typeError: "{file} имеет недопустимый формат. Пожалуйста, выберите файл с расширением jpg, jpeg, png или pdf."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", "pdf", "webp"],
                        sizeLimit: 5 * 1024 * 1024
                    },
                    callbacks: {
                        onSubmit: function () {
                            return !_this.isLoading();
                        },
                        onSubmitted: function () {
                            _this.isLoading(true);
                        },
                        onCancel: function () {
                            _this.isLoading(false);
                        },
                        onError: function () {
                            _this.isLoading(false);
                        },
                        onComplete: function (id, name, response) {
                            _this.isLoading(false);
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            _this.exclusiveScanCopies.push(response.data);
                        }
                    }
                });
            });
        }
        ViewModel.prototype.stopSales = function () {
            var _this = this;
            this.showModal({
                title: "Остановка продаж",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0434\u0430\u0436\u0443 \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u044F \u0438 \u043E\u043F\u0443\u0431\u043B\u0438\u043A\u043E\u0432\u0430\u0442\u044C \u0435\u0433\u043E \u0432 <b>\u0441\u0432\u043E\u0431\u043E\u0434\u043D\u043E\u043C \u0434\u043E\u0441\u0442\u0443\u043F\u0435</b>?",
                maxWidth: "400px",
                type: modalDialog_1.ModalType.ConfirmDelete,
                deleteBtnText: "Остановить продажу",
                onSubmit: function () {
                    _this.submit(document.getElementById("editSales"), { Price: 0 });
                }
            });
        };
        ViewModel.prototype.startSales = function () {
            var _this = this;
            var message = "Важно: стоимость произведения можно менять <b>не чаще 1 раза в месяц</b>";
            if (!(this.finished)) {
                message += "<br/> Пожалуйста, обратите внимание, что книгу нужно завершить за <b>6 месяцев</b> с момента старта подписки.";
            }
            this.showModal({
                title: "Начало продаж",
                message: message,
                maxWidth: "400px",
                type: modalDialog_1.ModalType.Confirm,
                okBtnText: "Начать продажи",
                onSubmit: function () {
                    _this.submit(document.getElementById("editSales"));
                }
            });
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.fullReloadPage();
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"../utils/stringUtils":69,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"toastr":199}],164:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.genres = ko.observableArray();
            this.exceptGenreIds = ko.observableArray();
            this.form = ko.observable();
            this.state = ko.observable();
            this.series = ko.observable();
            this.access = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.contestId = ko.observable();
            this.viewMode = ko.observable();
            this.hideFinished = ko.observable(false);
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var genres = _this.genres(), exceptGenreIds = _this.exceptGenreIds(), form = _this.form(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), access = _this.access(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), cntst = _this.contestId(), view = _this.viewMode(), fnd = _this.hideFinished();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                var formatUrlPart = "";
                var formUrlPart = "";
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (format !== "any" || form !== "any") {
                    formatUrlPart = "/" + format;
                }
                if (form !== "any") {
                    formUrlPart = "/" + form;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                else if (options.rp !== "today") {
                    params.rp = options.rp;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (access !== "any") {
                    params.access = access;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (duration !== "any" && format === "audiobook") {
                    params.duration = duration;
                }
                if (length !== "any" && format === "ebook") {
                    params.length = length;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                if (cntst) {
                    params.cntst = cntst;
                }
                params.fnd = fnd;
                var genreCodes;
                if (genres && genres.length > 0) {
                    genreCodes = genres.join("&");
                }
                else {
                    genreCodes = "all";
                }
                var url = app.rootUrl + ("work/genre/" + genreCodes + formatUrlPart + formUrlPart + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],165:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/validatedViewModel", "../utils/giftCodeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var giftCodeUtils_1 = require("../utils/giftCodeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            _super.call(this, options);
            giftCodeUtils_1.default.init();
        }
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/giftCodeUtils":55,"./base/validatedViewModel":93}],166:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "numeral", "./base/baseViewModel", "../utils/ajaxUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var numeral = require("numeral");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var Masonry = require("masonry-layout");
    var imagesLoaded = require("imagesloaded");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.copyDownloaded = ko.observable();
            this.numeral = numeral;
            this.initUploader = function (endpoint) {
                var uploader = new qq.FineUploader({
                    //debug: true,
                    multiple: false,
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: endpoint,
                        customHeaders: ajaxUtils_1.AjaxUtils.getHeaders(),
                        params: {
                            form: _this.options.workForm
                        }
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "{file} слишком большой, максимальный размер файла — {sizeLimit}.",
                        typeError: "{file} имеет недопустимый формат. Пожалуйста, выберите файл с расширением .fb2 или .zip."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл"
                    },
                    validation: {
                        allowedExtensions: ["fb2", "zip"],
                        sizeLimit: _this.options.maxWorkFileUploadSize
                    },
                    callbacks: {
                        onSubmit: function () {
                            return !_this.isLoading();
                        },
                        onSubmitted: function () {
                            _this.isLoading(true);
                        },
                        onCancel: function () {
                            _this.isLoading(false);
                        },
                        onError: function () {
                            _this.isLoading(false);
                        },
                        onComplete: function (id, name, response) {
                            _this.isLoading(false);
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            _this.redirectToPage(response.data.redirectUrl);
                        }
                    }
                });
            };
            var endpoint = window["app"].rootUrl + "work/processFb2";
            if (options.id) {
                endpoint = endpoint + "?" + $.param({ id: options.id });
                var subscription = this.copyDownloaded.subscribe(function (val) {
                    if (val) {
                        setTimeout(function () {
                            _this.initUploader(endpoint);
                        }, 50);
                        subscription.dispose();
                    }
                });
                return;
            }
            $(document).ready(function () {
                _this.initUploader(endpoint);
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"./base/baseViewModel":92,"imagesloaded":212,"jquery":214,"knockout":191,"masonry-layout":217,"numeral":220}],167:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.genres = ko.observableArray();
            this.exceptGenreIds = ko.observableArray();
            this.form = ko.observable();
            this.state = ko.observable();
            this.series = ko.observable();
            this.access = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.viewMode = ko.observable();
            this.contestId = ko.observable();
            this.hideFinished = ko.observable(false);
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var genres = _this.genres(), exceptGenreIds = _this.exceptGenreIds(), form = _this.form(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), access = _this.access(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), cntst = _this.contestId(), view = _this.viewMode(), fnd = _this.hideFinished();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                else if (options.rp !== "today") {
                    params.rp = options.rp;
                }
                if (format !== "any") {
                    params.format = format;
                }
                if (form !== "any") {
                    params.form = form;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (access !== "any") {
                    params.access = access;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (duration !== "any" && format == "audiobook") {
                    params.duration = duration;
                }
                if (length !== "any" && format == "ebook") {
                    params.length = length;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                if (cntst) {
                    params.cntst = cntst;
                }
                params.fnd = fnd;
                var genreCodes;
                if (genres && genres.length > 0) {
                    genreCodes = genres.join("&");
                }
                else {
                    genreCodes = "all";
                }
                var url = app.rootUrl + ("work/recommended/" + genreCodes + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],168:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.forms = ko.observableArray([
                {
                    id: "story",
                    name: "Рассказ",
                    description: "Малая форма произведения.<br/> Состоит из одной части."
                },
                {
                    id: "tale",
                    name: "Повесть",
                    description: "Средняя форма произведения.<br/> Состоит из нескольких частей."
                },
                {
                    id: "novel",
                    name: "Роман",
                    description: "Большая форма произведения.<br/> Состоит из нескольких частей."
                },
                {
                    id: "storyBook",
                    name: "Сборник рассказов",
                    description: "Состоит из нескольких рассказов. <br/> Пожалуйста, придерживайтесь правила одна часть - один рассказ."
                },
                {
                    id: "poetry",
                    name: "Сборник поэзии",
                    description: "Состоит из нескольких стихотворений или других произведений в жанре поэзия."
                }]);
            this.selectedFormat = ko.observable(null);
            this.selectedForm = ko.observable(null);
            this.formData = ko.pureComputed(function () {
                var data = {
                    form: _this.selectedForm
                };
                var format = _this.selectedFormat();
                if (_this.options.isAdminOrAudioPublisher) {
                    data.format = format;
                }
                return data;
            });
            this.toggleForm = function (form) {
                if (_this.selectedForm() === null || _this.selectedForm() !== form.id) {
                    _this.selectedForm(form.id);
                }
                else {
                    _this.selectedForm(null);
                }
            };
            if (options.isAdminOrTranslator) {
                this.forms.push({
                    id: "translation",
                    name: "Перевод",
                    description: "Перевод книги с иностранного языка на русский."
                });
            }
        }
        ViewModel.prototype.nextBtnClick = function () {
            var formId = this.selectedForm();
            if (!formId)
                return;
            var url = window["app"].rootUrl + "work/create?" + $.param(this.formData());
            this.redirectToPage(url);
        };
        ViewModel.prototype.importBtnClick = function () {
            if (!this.selectedForm() || (this.selectedFormat() && this.selectedFormat() !== "ebook"))
                return;
            var url = window["app"].rootUrl + "work/import?" + $.param(this.formData());
            this.redirectToPage(url);
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92,"jquery":214,"knockout":191}],169:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel() {
            _super.call(this);
        }
        ViewModel.prototype.showAuthModal = function () {
            app.ensureAuth(true);
        };
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92}],170:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "toastr", "sortable", "../utils/ajaxUtils", "./base/validatedViewModel", "../utils/windowUtils", "../utils/stringUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var toastr = require("toastr");
    var Sortable = require("sortable");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var windowUtils_1 = require("../utils/windowUtils");
    var stringUtils_1 = require("../utils/stringUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.titleMaxLength = 50;
            this.textMaxLength = 1000;
            this.recommendationMaxLength = 200;
            this.seriesId = this.options.seriesId;
            this.enableSorting = ko.observable();
            this.title = ko.observable().extend({
                required: true,
                maxLength: this.titleMaxLength
            });
            this.titleHint = ko.pureComputed(function () {
                var title = _this.title() || "";
                var characters = title.length;
                return characters + "/" + _this.titleMaxLength;
            });
            this.description = ko.observable().extend({
                maxLength: {
                    params: this.textMaxLength,
                    message: "Длина поля должна быть не больше {0} символов."
                }
            });
            this.descriptionHint = ko.pureComputed(function () {
                var description = _this.description() || "";
                return description.length + "/" + _this.textMaxLength;
            });
            this.recommendation = ko.observable().extend({
                maxLength: {
                    params: this.recommendationMaxLength,
                    message: "Длина поля должна быть не больше {0} символов."
                }
            });
            this.recommendationHint = ko.pureComputed(function () {
                var recommendation = _this.recommendation() || "";
                return recommendation.length + "/" + _this.recommendationMaxLength;
            });
            this.discount = ko.observable();
            this.titleInit = options.titleInit || "";
            this.descriptionInit = options.descriptionInit || "";
            this.recommendationInit = options.recommendationInit || "";
            this.discountInit = options.discount;
            this.totalSumInit = options.totalSum;
            this.isDiscountEnabled = options.isDiscountEnabled;
            this.limitDiscount = options.limitDiscount;
            this.isModeratorOrAdmin = options.isModeratorOrAdmin;
            setTimeout(function () {
                _this.initValidation();
            }, 0);
            ko.computed(function () {
                var description = _this.description() || "";
                var recommendation = _this.recommendation() || "";
                var title = _this.title() || "";
                if (stringUtils_1.default.compareWithoutLineBreaks(description, _this.descriptionInit)
                    || stringUtils_1.default.compareWithoutLineBreaks(recommendation, _this.recommendationInit)
                    || stringUtils_1.default.compareWithoutLineBreaks(title, _this.titleInit)) {
                    windowUtils_1.default.setDirty();
                }
                else {
                    windowUtils_1.default.setDirty(false);
                }
            });
            var ul = $(".sortable")[0];
            if (ul) {
                var sortable = new Sortable(ul, {
                    animation: 150,
                    filter: ".btn",
                    handle: ".sortable-handle",
                    onEnd: function (e) {
                        ajaxUtils_1.AjaxUtils.post("work/series/reorderWork", {
                            seriesId: _this.seriesId,
                            oldIndex: e.oldIndex,
                            newIndex: e.newIndex
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                toastr.success("Порядок произведений был изменен.");
                            }
                            else {
                                toastr.error(result.messages[0]);
                            }
                        });
                    }
                });
            }
        }
        ViewModel.prototype.showDeleteWorkModal = function (id, title) {
            var _this = this;
            this.showModal({
                title: "Удаление произведение из цикла",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0440\u043E\u0438\u0437\u0432\u0435\u0434\u0435\u043D\u0438\u0435 \u00AB" + title + "\u00BB \u0438\u0437 \u0446\u0438\u043A\u043B\u0430?",
                minWidth: "300px",
                onSubmit: function () {
                    return ajaxUtils_1.AjaxUtils.post("work/removeFromSeries", {
                        id: id
                    }).done(function (result) {
                        if (result.isSuccessful) {
                            toastr.success(result.messages[0]);
                            _this.modal.hide();
                            $("#work_" + id).fadeOut("normal", function () {
                                $(this).remove();
                            });
                        }
                        else {
                            _this.modal.errorMessages(result.messages);
                        }
                    });
                }
            });
        };
        ViewModel.prototype.save = function (formElement, extendedData) {
            var _this = this;
            if (!this.isModeratorOrAdmin && this.limitDiscount > 0 && this.isDiscountEnabled && this.discount() != this.discountInit) {
                var message = "\u0412\u044B \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0435 \u0441\u043A\u0438\u0434\u043A\u0443 <b>" + this.discount() + "%</b> \u043D\u0430 \u0446\u0438\u043A\u043B. \u0421\u043A\u0438\u0434\u043A\u0443 \u043C\u043E\u0436\u043D\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0447\u0435\u0440\u0435\u0437 <b>" + this.limitDiscount + " " + stringUtils_1.default.pluralize(this.limitDiscount, ["день", "дня", "дней"]) + "</b> \u0438\u043B\u0438 \u0447\u0435\u0440\u0435\u0437 \u0441\u043B\u0443\u0436\u0431\u0443 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0438.";
                var totalSumWithDiscount = this.totalSumInit - (this.totalSumInit * this.discount() / 100);
                if (totalSumWithDiscount > 0) {
                    message = message + " C\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C \u043F\u043E\u043A\u0443\u043F\u043A\u0438 \u0432\u0441\u0435\u0433\u043E \u0446\u0438\u043A\u043B\u0430 \u0441 \u0443\u0447\u0435\u0442\u043E\u043C \u0441\u043A\u0438\u0434\u043A\u0438 \u0431\u0443\u0434\u0435\u0442 <b>" + totalSumWithDiscount.toFixed(2) + " \u20BD</b>.";
                }
                this.showModal({
                    title: "Изменение скидки на цикл",
                    message: message,
                    minWidth: "300px",
                    maxWidth: "600px",
                    type: 2,
                    onSubmit: function () {
                        _this.modal.hide();
                        _this.submit(formElement, extendedData);
                    }
                });
            }
            else {
                this.submit(formElement, extendedData);
            }
        };
        ViewModel.prototype.onSubmitSucess = function (result) {
            this.forceRedirectToPage(result.data.redirectUrl);
        };
        return ViewModel;
    }(validatedViewModel_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/stringUtils":69,"../utils/windowUtils":72,"./base/validatedViewModel":93,"jquery":214,"knockout":191,"sortable":196,"toastr":199}],171:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "./base/baseViewModel"], factory);
    }
})(function (require, exports) {
    "use strict";
    var baseViewModel_1 = require("./base/baseViewModel");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel() {
            _super.call(this);
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"./base/baseViewModel":92}],172:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "js.cookie", "./base/baseViewModel", "../utils/dateTimeUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var Cookies = require("js.cookie");
    var baseViewModel_1 = require("./base/baseViewModel");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.moreFilters = ko.observable(this.options.showMoreFilters);
            this.isLoading = ko.observable(false);
            this.form = ko.observable();
            this.exceptGenreIds = ko.observableArray();
            this.state = ko.observable();
            this.series = ko.observable();
            this.access = ko.observable();
            this.download = ko.observable();
            this.lastUpdate = ko.observable();
            this.published = ko.observable();
            this.format = ko.observable();
            this.duration = ko.observable();
            this.length = ko.observable();
            this.contestId = ko.observable();
            this.viewMode = ko.observable();
            this.hideFinished = ko.observable(false);
            this.seriesOrder = ko.observable();
            this.rp = ko.observable();
            this.toggleMoreFilters = function () {
                _this.moreFilters(!_this.moreFilters());
                if (_this.moreFilters()) {
                    $("#moreFilters").addClass("in");
                }
                else {
                    $("#moreFilters").removeClass("in");
                }
            };
            this.switchView = function (mode) {
                _this.viewMode(mode);
            };
            var initialized = false;
            this.viewMode(options.viewMode);
            var defaultViewMode = Cookies.get("at.workView") || "list";
            ko.computed(function () {
                var form = _this.form(), exceptGenreIds = _this.exceptGenreIds(), state = _this.state(), series = _this.series(), seriesOrder = _this.seriesOrder(), access = _this.access(), dnl = _this.download(), upd = _this.lastUpdate(), pub = _this.published(), format = _this.format(), duration = _this.duration(), length = _this.length(), cntst = _this.contestId(), view = _this.viewMode(), fnd = _this.hideFinished();
                if (!initialized) {
                    return;
                }
                if (series === "out" && seriesOrder != "any") {
                    _this.seriesOrder("any");
                    return;
                }
                var params = {};
                if (view !== defaultViewMode) {
                    params.view = view;
                    defaultViewMode = view;
                    // Сохраняем страницу только при смене вида отображения книг
                    if (options.page && options.page > 1) {
                        params.page = options.page;
                    }
                }
                else {
                    options.page = 1;
                }
                if (format !== "any") {
                    params.format = format;
                }
                if (form !== "any") {
                    params.form = form;
                }
                if (options.sorting !== "popular") {
                    params.sorting = options.sorting;
                }
                else if (options.rp !== "today") {
                    params.rp = options.rp;
                }
                if (state !== "any") {
                    params.state = state;
                }
                if (series !== "any") {
                    params.series = series;
                }
                if (access !== "any") {
                    params.access = access;
                }
                if (dnl !== "any") {
                    params.dnl = dnl;
                }
                if (upd !== "-1") {
                    params.upd = upd;
                }
                if (pub !== "-1") {
                    params.pub = pub;
                }
                if (duration !== "any" && format === "audiobook") {
                    params.duration = duration;
                }
                if (length !== "any" && format === "ebook") {
                    params.length = length;
                }
                if (seriesOrder !== "any") {
                    params.seriesOrder = seriesOrder;
                }
                if (exceptGenreIds) {
                    params.eg = exceptGenreIds.join("-");
                }
                else {
                    params.eg = "";
                }
                if (cntst) {
                    params.cntst = cntst;
                }
                params.fnd = fnd;
                var url = app.rootUrl + ("work/tag/" + options.tag + "?" + $.param(params));
                $.pjax({ url: url, container: "#search-results", fragment: "#search-results" });
            });
            setTimeout(function () {
                initialized = true;
            }, 200);
            $(document)
                .on("pjax:send", function () {
                _this.isLoading(true);
            })
                .on("pjax:complete", function () {
                _this.isLoading(false);
                dateTimeUtils_1.default.displayTime();
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/dateTimeUtils":52,"./base/baseViewModel":92,"jquery":214,"js.cookie":215,"knockout":191}],173:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "lodash", "toastr", "numeral", "./base/baseViewModel", "./base/validatedViewModel", "../utils/ajaxUtils", "../components/modalDialog"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var _ = require("lodash");
    var toastr = require("toastr");
    var numeral = require("numeral");
    var baseViewModel_1 = require("./base/baseViewModel");
    var validatedViewModel_1 = require("./base/validatedViewModel");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var modalDialog_1 = require("../components/modalDialog");
    var Masonry = require("masonry-layout");
    var imagesLoaded = require("imagesloaded");
    var WorkGallery = (function (_super) {
        __extends(WorkGallery, _super);
        function WorkGallery(options) {
            _super.call(this, options);
            this.caption = ko.observable().extend({
                maxLength: 200
            });
            this.processing = ko.observable(false);
            this.id = options.id;
            this.workId = options.workId;
            this.caption(options.caption);
            this.originalCaption = options.caption;
            this.uploadTime = options.uploadTime;
            this.url = options.filePath;
            this.initValidation();
        }
        WorkGallery.prototype.startEditing = function () {
            this.originalCaption = this.caption();
            this.showModal({
                title: "Комментарий к иллюстрации",
                type: modalDialog_1.ModalType.Custom,
                templateId: "workGalleryCaptionModal",
                minWidth: "400px",
                maxWidth: "500px",
                viewModel: this
            });
        };
        WorkGallery.prototype.cancelEditing = function () {
            this.caption(this.originalCaption);
            this.modal.hide();
        };
        WorkGallery.prototype.submit = function () {
            var _this = this;
            if (this.validation !== undefined && !this.validation.isValid()) {
                this.validation.errors.showAllMessages();
                return;
            }
            ;
            if (this.processing())
                return;
            this.processing(true);
            this.errorMessages([]);
            ajaxUtils_1.AjaxUtils.post("file/updateWorkGallery", {
                id: this.id,
                caption: this.caption()
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success("\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0431\u044B\u043B\u043E \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043E.");
                    _this.caption(result.data.caption);
                    _this.originalCaption = _this.caption();
                }
                else {
                    toastr.error(result.messages[0]);
                }
                _this.processing(false);
                _this.modal.hide();
            }).always(function () {
                _this.processing(false);
            });
        };
        return WorkGallery;
    }(validatedViewModel_1.default));
    var WorkUpload = (function () {
        function WorkUpload(options) {
            this.title = ko.observable();
            this.isEditing = ko.observable(false);
            this.processing = ko.observable(false);
            this.id = options.id;
            this.workId = options.workId;
            this.title(options.title);
            this.originalTitle = options.title;
            this.extension = options.extension;
            this.size = options.size;
            this.uploadTime = options.uploadTime;
            this.downloadCount = options.downloadCount;
            this.url = options.url;
        }
        WorkUpload.prototype.startEditing = function () {
            this.originalTitle = this.title();
            this.isEditing(true);
        };
        WorkUpload.prototype.cancelEditing = function () {
            this.title(this.originalTitle);
            this.isEditing(false);
        };
        WorkUpload.prototype.save = function () {
            var _this = this;
            this.processing(true);
            return ajaxUtils_1.AjaxUtils.post("file/renameWorkFile", {
                id: this.id,
                title: this.title()
            }).done(function (result) {
                if (result.isSuccessful) {
                    toastr.success("\u0424\u0430\u0439\u043B \u0431\u044B\u043B \u043F\u0435\u0440\u0435\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D. \u041D\u043E\u0432\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435: \u00AB" + result.data.title + "\u00BB");
                    _this.title(result.data.title);
                }
                else {
                    toastr.error(result.messages[0]);
                }
                _this.isEditing(false);
            }).always(function () {
                _this.processing(false);
            });
        };
        return WorkUpload;
    }());
    var BooktrailerVideoUrl = (function () {
        function BooktrailerVideoUrl(options, viewModel) {
            var _this = this;
            this.workId = ko.observable();
            this.savedUrl = ko.observable("");
            this.url = ko.observable("");
            this.editing = ko.computed(function () {
                return _this.savedUrl() !== _this.url();
            });
            this.url(options.booktrailerVideoUrl);
            this.savedUrl(this.url());
            this.workId(options.workId);
            this.viewModel = viewModel;
        }
        BooktrailerVideoUrl.prototype.save = function () {
            var _this = this;
            return ajaxUtils_1.AjaxUtils.post("work/saveBooktrailerVideoUrl", {
                id: this.workId(),
                url: this.url()
            }).done(function (result) {
                if (result.isSuccessful) {
                    _this.savedUrl(_this.url());
                    toastr.success(result.messages[0]);
                }
                else {
                    toastr.error(result.messages[0]);
                }
            });
        };
        BooktrailerVideoUrl.prototype.cancel = function () {
            this.url(this.savedUrl());
        };
        BooktrailerVideoUrl.prototype.clear = function () {
            var _this = this;
            this.viewModel.showModal({
                title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0441\u0441\u044B\u043B\u043A\u0438 \u043D\u0430 \u0432\u0438\u0434\u0435\u043E",
                message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u0432\u0438\u0434\u0435\u043E?",
                maxWidth: "400px",
                onSubmit: function () {
                    _this.url("");
                    return _this.save();
                }
            });
        };
        return BooktrailerVideoUrl;
    }());
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.isLoading = ko.observable(false);
            this.files = ko.observableArray([]);
            this.audioFiles = ko.observableArray([]);
            this.galleryImages = ko.observableArray([]);
            this.booktrailerVideoUrl = ko.observable();
            this.numeral = numeral;
            this.deleteFile = function (file) {
                var fileName = file.title() + "." + file.extension;
                _this.showModal({
                    title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u0430",
                    message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0444\u0430\u0439\u043B \u00AB" + fileName + "\u00BB?",
                    maxWidth: "400px",
                    onSubmit: function () {
                        return ajaxUtils_1.AjaxUtils.post("file/deleteWorkUpload", {
                            id: file.id
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                var $el = $("#" + file.id);
                                $el.hide({
                                    done: function () {
                                        $el.fadeOut();
                                        _this.files.remove(file);
                                        _this.audioFiles.remove(file);
                                    }
                                });
                                toastr.success("\u0424\u0430\u0439\u043B \u00AB" + fileName + "\u00BB \u0431\u044B\u043B \u0443\u0434\u0430\u043B\u0435\u043D.");
                            }
                        });
                    }
                });
            };
            this.deleteGalleryImage = function (file) {
                _this.showModal({
                    title: "\u0423\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0438\u043B\u043B\u044E\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
                    message: "\u0412\u044B \u0442\u043E\u0447\u043D\u043E \u0445\u043E\u0442\u0438\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0438\u043B\u043B\u044E\u0441\u0442\u0440\u0430\u0446\u0438\u044E?",
                    maxWidth: "400px",
                    onSubmit: function () {
                        return ajaxUtils_1.AjaxUtils.post("file/deleteWorkGallery", {
                            id: file.id
                        }).done(function (result) {
                            if (result.isSuccessful) {
                                _this.galleryImages.remove(file);
                                setTimeout(function () {
                                    Masonry.data("#masonry").layout();
                                }, 100);
                                toastr.success("\u0418\u043B\u043B\u044E\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u0431\u044B\u043B\u0430 \u0443\u0434\u0430\u043B\u0435\u043D\u0430.");
                            }
                        });
                    }
                });
            };
            this.files(_.map(_.filter(options.uploads, function (f) { return !f.isAudio && !f.isGallery; }), function (x) { return new WorkUpload(x); }));
            this.audioFiles(_.map(_.filter(options.uploads, function (f) { return f.isAudio; }), function (x) { return new WorkUpload(x); }));
            this.galleryImages(_.map(options.galleryImages, function (x) { return new WorkGallery(x); }));
            this.booktrailerVideoUrl(new BooktrailerVideoUrl(options, this));
            var endpoint = window["app"].rootUrl + "file/uploadWorkFiles";
            $(document).ready(function () {
                var masonry = new Masonry("#masonry", {
                    itemSelector: ".item",
                    gutter: 10,
                    columnWidth: 250
                });
                $("#masonry .item")["imagesLoaded"]().progress(function () {
                    masonry.layout();
                });
                $(window).on("resize", function () {
                    setTimeout(function () { return masonry.layout(); }, 200);
                });
                var uploader = new qq.FineUploader({
                    //debug: true,
                    element: document.getElementById("fine-uploader"),
                    request: {
                        endpoint: endpoint,
                        params: {
                            id: options.workId
                        }
                    },
                    thumbnails: {
                        placeholders: {
                            notAvailablePath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/not_available-generic.png",
                            waitingPath: window["app"].rootUrl +
                                "dist/vendor/fine-uploader/placeholders/waiting-generic.png"
                        }
                    },
                    messages: {
                        unsupportedBrowser: "Ваш браузер не поддерживает загрузку файлов.",
                        sizeError: "\u0424\u0430\u0439\u043B \u00AB{file}\u00BB \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439, \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0444\u0430\u0439\u043B\u0430 \u2014 " + options.maxWorkFileUploadSize / (1024 * 1024) + "\u041C\u0411.",
                        typeError: "Файл «{file}» имеет недопустимый формат. Разрешены следующие форматы: {extensions}.",
                        tooManyItemsError: "\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043D\u0435 \u0431\u043E\u043B\u0435\u0435 " + options.maxWorkFileUploads + " \u0444\u0430\u0439\u043B\u043E\u0432."
                    },
                    text: {
                        failUpload: "Не удалось загрузить файл",
                        waitingForResponse: "Обработка..."
                    },
                    validation: {
                        allowedExtensions: ["jpg", "jpeg", "png", "webp"],
                        sizeLimit: options.maxWorkFileUploadSize,
                        itemLimit: options.maxWorkFileUploads - _this.files().length + _this.audioFiles().length
                    },
                    callbacks: {
                        onComplete: function (id, name, response) {
                            if (!response.success) {
                                alert(response.error);
                                return;
                            }
                            $("[qq-file-id=" + id + "]").remove();
                            if (response.data.width && response.data.height) {
                                _this.galleryImages.push(new WorkGallery(response.data));
                                setTimeout(function () {
                                    masonry.appended($(".item").last());
                                    setTimeout(function () {
                                        masonry.layout();
                                    }, 500);
                                });
                            }
                            else if (response.data.isAudio) {
                                _this.audioFiles.push(new WorkUpload(response.data));
                            }
                            else {
                                _this.files.push(new WorkUpload(response.data));
                            }
                        }
                    }
                });
                ko.computed(function () {
                    var itemLimit = options.maxWorkFileUploads - _this.files().length + _this.audioFiles().length + _this.galleryImages.length;
                    if (itemLimit === 0) {
                        itemLimit = -1;
                    }
                    uploader.setItemLimit(itemLimit);
                });
            });
        }
        return ViewModel;
    }(baseViewModel_1.BaseViewModel));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../components/modalDialog":20,"../utils/ajaxUtils":45,"./base/baseViewModel":92,"./base/validatedViewModel":93,"imagesloaded":212,"jquery":214,"knockout":191,"lodash":216,"masonry-layout":217,"numeral":220,"toastr":199}],174:[function(require,module,exports){
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
(function (factory) {
    if (typeof module === 'object' && typeof module.exports === 'object') {
        var v = factory(require, exports); if (v !== undefined) module.exports = v;
    }
    else if (typeof define === 'function' && define.amd) {
        define(["require", "exports", "jquery", "knockout", "moment", "numeral", "../utils/ajaxUtils", "../utils/dateTimeUtils", "../utils/socialUtils", "../utils/localStorageUtils", "../utils/imageZoomUtils", "./commentsView", "../utils/richContentUtils"], factory);
    }
})(function (require, exports) {
    "use strict";
    var $ = require("jquery");
    var ko = require("knockout");
    var moment = require("moment");
    var numeral = require("numeral");
    var ajaxUtils_1 = require("../utils/ajaxUtils");
    var dateTimeUtils_1 = require("../utils/dateTimeUtils");
    var socialUtils_1 = require("../utils/socialUtils");
    var scriptjs = require("scriptjs");
    var localStorageUtils_1 = require("../utils/localStorageUtils");
    var imageZoomUtils_1 = require("../utils/imageZoomUtils");
    var commentsView_1 = require("./commentsView");
    var richContentUtils_1 = require("../utils/richContentUtils");
    //declare var PhotoSwipe;
    //declare var PhotoSwipeUI_Default;
    var Masonry = require("masonry-layout");
    var imagesLoaded = require("imagesloaded");
    var ViewModel = (function (_super) {
        __extends(ViewModel, _super);
        //private clipboard = null;
        function ViewModel(options) {
            var _this = this;
            _super.call(this, options);
            this.numeral = numeral;
            //photoSwipe = null;
            this.processing = ko.observable(false);
            this.workId = this.options.workId;
            this.isATRecommended = this.options.isATRecommended;
            this.isBiblioNight = this.options.isBiblioNight;
            this.startDate = ko.observable(moment().startOf("day").add(-6, "days"));
            this.endDate = ko.observable(moment().endOf("day"));
            this.isLoading = ko.observable(true);
            this.statsViewCount = ko.observable(0);
            this.statsCommentCount = ko.observable(0);
            this.statsLikeCount = ko.observable(0);
            this.statsFilterData = ko.computed(function () {
                var filterData = {
                    startDate: _this.startDate().toISOString(),
                    endDate: _this.endDate().toISOString(),
                    itemId: _this.workId,
                    groupBy: "work"
                };
                return filterData;
            });
            this.booktrailerVideoUrl = ko.observable();
            this.showFullStats = ko.observable();
            this.statsInit = false;
            this.workStatLoaded = ko.observable(false);
            this.totalCount = ko.observable(0);
            this.readingCount = ko.observable(0);
            this.savedCount = ko.observable(0);
            this.finishedCount = ko.observable(0);
            this.dislikedCount = ko.observable(0);
            this.timelineLoaded = ko.observable(false);
            this.timelineHtml = ko.observable();
            socialUtils_1.default.init();
            richContentUtils_1.default.processHtml(".annotation");
            localStorageUtils_1.default.addToList(localStorageUtils_1.default.RecentlyViewedKey, this.workId);
            this.booktrailerVideoUrl(options.booktrailerVideoUrl);
            this.showFullStats(options.showFullStats);
            this.loadComments(null, null, false);
        }
        ViewModel.prototype.showMaterialsTab = function () {
            $("#href-tab-maretials").tab("show");
            setTimeout(function () {
                var $audio = $("audio");
                if ($audio.length > 0) {
                    $audio["mediaelementplayer"]({
                        audioWidth: "100%",
                        features: ["playpause", "progress", "current", "duration", "tracks", "volume"]
                    });
                }
                if (!$("#masonry")[0])
                    return;
                var masonry = new Masonry("#masonry", {
                    itemSelector: "figure",
                    gutter: 10,
                    columnWidth: ".grid-sizer",
                    percentPosition: true
                });
                $("#masonry figure")["imagesLoaded"]()
                    .progress(function () {
                    masonry.layout();
                });
                $(window)
                    .on("resize", function () {
                    setTimeout(function () { return masonry.layout(); }, 200);
                });
                imageZoomUtils_1.default.initWorkMaterials();
            }, 200);
        };
        /** Загружает информацию для вкладки "Статистика" */
        ViewModel.prototype.showStatsTab = function () {
            var _this = this;
            $("#href-tab-stats").tab("show");
            if (this.statsInit)
                return;
            ajaxUtils_1.AjaxUtils.get("work/work-stats", { workId: this.workId })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.totalCount(result.data.totalCount);
                _this.readingCount(result.data.readingCount);
                _this.savedCount(result.data.savedCount);
                _this.finishedCount(result.data.finishedCount);
                _this.dislikedCount(result.data.dislikedCount);
            })
                .always(function () {
                _this.workStatLoaded(true);
            });
            if (this.showFullStats()) {
                scriptjs([ajaxUtils_1.AjaxUtils.getFullUrl("dist/js/amcharts?v=140717")], function () {
                    ko.computed(function () {
                        _this.isLoading(true);
                        _this.statsFilterData();
                        _this.loadDynamicChart();
                    });
                    _this.statsInit = true;
                });
            }
            else {
                this.statsInit = true;
            }
        };
        ViewModel.prototype.showTimelineTab = function () {
            var _this = this;
            $("#href-tab-timeline").tab("show");
            if (this.timelineLoaded())
                return;
            ajaxUtils_1.AjaxUtils.get("work/timeline", { id: this.workId })
                .done(function (result) {
                if (!result.isSuccessful) {
                    alert(result.messages[0]);
                    return;
                }
                _this.timelineHtml(result.data.html);
                setTimeout(function () {
                    var $timeline = $("#tab-timeline").find(".widget-content");
                    $timeline.addClass("in");
                    dateTimeUtils_1.default.displayTime($timeline);
                }, 0);
            })
                .always(function () {
                _this.timelineLoaded(true);
            });
        };
        ViewModel.prototype.loadDynamicChart = function () {
            var _this = this;
            ajaxUtils_1.AjaxUtils.get("report/user-activity-data", this.statsFilterData())
                .done(function (result) {
                var daysInPerios = Math.floor((_this.endDate() - _this.startDate()) / (1000 * 60 * 60 * 24));
                var minPeriod = "DD";
                var categoryBalloonDateFormat = "MMMM DD, YYYY";
                if (daysInPerios > 40) {
                    minPeriod = "MM";
                    categoryBalloonDateFormat = "MMMM, YYYY";
                }
                _this.dynamicChart = AmCharts.makeChart("statsChartdiv", {
                    language: "ru",
                    type: "serial",
                    theme: "light",
                    valueAxes: [
                        {
                            id: "countAxis",
                            axisAlpha: 0,
                            position: "left",
                            integersOnly: true,
                            title: "Количество просмотров"
                        }, {
                            title: "Время чтения, часы",
                            id: "durationAxis",
                            axisAlpha: 0,
                            gridAlpha: 0,
                            position: "right"
                        }
                    ],
                    graphs: [
                        {
                            balloonText: "Просмотров: [[value]]",
                            fillAlphas: 0.7,
                            legendValueText: "[[value]]",
                            type: "column",
                            valueField: "totalViewCount",
                            valueAxis: "countAxis"
                        }, {
                            balloonText: "Время чтения: [[value]]",
                            type: "smoothedLine",
                            bullet: "round",
                            bulletBorderAlpha: 1,
                            useLineColorForBulletBorder: true,
                            bulletColor: "#FFFFFF",
                            hideBulletsCount: 30,
                            legendValueText: "[[value]] ч.",
                            fillAlphas: 0,
                            valueField: "spentTime",
                            valueAxis: "durationAxis"
                        }
                    ],
                    chartCursor: {
                        categoryBalloonDateFormat: categoryBalloonDateFormat,
                        cursorAlpha: 0.1,
                        cursorColor: "#000000",
                        fullWidth: true,
                        valueBalloonsEnabled: false,
                        zoomable: false
                    },
                    dataDateFormat: "DD.MM.YYYY",
                    categoryField: "date",
                    categoryAxis: {
                        parseDates: true,
                        dashLength: 1,
                        minorGridEnabled: true,
                        minPeriod: minPeriod
                    },
                    legend: {
                        equalWidths: false,
                        useGraphSettings: true,
                        align: "center"
                    },
                    dataProvider: result.data,
                    pathToImages: window["app"].rootUrl + "dist/vendor/amcharts/images/"
                });
                _this.isLoading(false);
            });
        };
        ViewModel.prototype.download = function (fileId) {
            var $button = $("#file_" + fileId);
            $button.attr("disabled", "disabled").addClass("is-loading");
            $.get(window["app"].rootUrl + "file/downloadWorkFile", { id: fileId })
                .done(function (result) {
                if (result.isSuccessful) {
                    var hiddenIFrameId = "hiddenDownloader";
                    var iframe = document.getElementById(hiddenIFrameId);
                    if (iframe === null) {
                        iframe = document.createElement("iframe");
                        iframe.id = hiddenIFrameId;
                        iframe.style.display = "none";
                        document.body.appendChild(iframe);
                    }
                    iframe["src"] = result.data;
                }
            })
                .always(function () {
                $button.removeAttr("disabled").removeClass("is-loading");
            });
        };
        ViewModel.prototype.updateLastTextLength = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateLastTextLength", {
                id: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        ViewModel.prototype.updateBookSize = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateBookSize", {
                workId: this.workId
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        ViewModel.prototype.updateATRecState = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateATRecomendation", {
                id: this.workId,
                isATRecommended: !this.isATRecommended
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        ViewModel.prototype.updateBiblioNightState = function () {
            var _this = this;
            this.processing(true);
            ajaxUtils_1.AjaxUtils.post("work/updateBiblioNight", {
                id: this.workId,
                isBiblioNight: !this.isBiblioNight
            }).done(function (result) {
                _this.processing(false);
                if (result.isSuccessful) {
                    _this.reloadPage();
                }
                else {
                    alert(result.messages[0]);
                }
            });
        };
        ViewModel.prototype.showAuthModal = function () {
            app.ensureAuth(true);
        };
        return ViewModel;
    }(commentsView_1.default));
    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = ViewModel;
});

},{"../utils/ajaxUtils":45,"../utils/dateTimeUtils":52,"../utils/imageZoomUtils":57,"../utils/localStorageUtils":59,"../utils/richContentUtils":67,"../utils/socialUtils":68,"./commentsView":99,"imagesloaded":212,"jquery":214,"knockout":191,"masonry-layout":217,"moment":219,"numeral":220,"scriptjs":194}],175:[function(require,module,exports){
/*!
 * Cropper v2.3.4
 * https://github.com/fengyuanchen/cropper
 *
 * Copyright (c) 2014-2016 Fengyuan Chen and contributors
 * Released under the MIT license
 *
 * Date: 2016-09-03T05:50:45.412Z
 */

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node / CommonJS
        factory(require('jquery'));
    } else {
        // Browser globals.
        factory(jQuery);
    }
})(function ($) {

    'use strict';

    // Globals
    var $window = $(window);
    var $document = $(document);
    var location = window.location;
    var navigator = window.navigator;
    var ArrayBuffer = window.ArrayBuffer;
    var Uint8Array = window.Uint8Array;
    var DataView = window.DataView;
    var btoa = window.btoa;

    // Constants
    var NAMESPACE = 'cropper';

    // Classes
    var CLASS_MODAL = 'cropper-modal';
    var CLASS_HIDE = 'cropper-hide';
    var CLASS_HIDDEN = 'cropper-hidden';
    var CLASS_INVISIBLE = 'cropper-invisible';
    var CLASS_MOVE = 'cropper-move';
    var CLASS_CROP = 'cropper-crop';
    var CLASS_DISABLED = 'cropper-disabled';
    var CLASS_BG = 'cropper-bg';

    // Events
    var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown';
    var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove';
    var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel';
    var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
    var EVENT_DBLCLICK = 'dblclick';
    var EVENT_LOAD = 'load.' + NAMESPACE;
    var EVENT_ERROR = 'error.' + NAMESPACE;
    var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace
    var EVENT_BUILD = 'build.' + NAMESPACE;
    var EVENT_BUILT = 'built.' + NAMESPACE;
    var EVENT_CROP_START = 'cropstart.' + NAMESPACE;
    var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE;
    var EVENT_CROP_END = 'cropend.' + NAMESPACE;
    var EVENT_CROP = 'crop.' + NAMESPACE;
    var EVENT_ZOOM = 'zoom.' + NAMESPACE;

    // RegExps
    var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/;
    var REGEXP_DATA_URL = /^data:/;
    var REGEXP_DATA_URL_HEAD = /^data:([^;]+);base64,/;
    var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg.*;base64,/;

    // Data keys
    var DATA_PREVIEW = 'preview';
    var DATA_ACTION = 'action';

    // Actions
    var ACTION_EAST = 'e';
    var ACTION_WEST = 'w';
    var ACTION_SOUTH = 's';
    var ACTION_NORTH = 'n';
    var ACTION_SOUTH_EAST = 'se';
    var ACTION_SOUTH_WEST = 'sw';
    var ACTION_NORTH_EAST = 'ne';
    var ACTION_NORTH_WEST = 'nw';
    var ACTION_ALL = 'all';
    var ACTION_CROP = 'crop';
    var ACTION_MOVE = 'move';
    var ACTION_ZOOM = 'zoom';
    var ACTION_NONE = 'none';

    // Supports
    var SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext);
    var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);

    // Maths
    var num = Number;
    var min = Math.min;
    var max = Math.max;
    var abs = Math.abs;
    var sin = Math.sin;
    var cos = Math.cos;
    var sqrt = Math.sqrt;
    var round = Math.round;
    var floor = Math.floor;

    // Utilities
    var fromCharCode = String.fromCharCode;

    function isNumber(n) {
        return typeof n === 'number' && !isNaN(n);
    }

    function isUndefined(n) {
        return typeof n === 'undefined';
    }

    function toArray(obj, offset) {
        var args = [];

        // This is necessary for IE8
        if (isNumber(offset)) {
            args.push(offset);
        }

        return args.slice.apply(obj, args);
    }

    // Custom proxy to avoid jQuery's guid
    function proxy(fn, context) {
        var args = toArray(arguments, 2);

        return function () {
            return fn.apply(context, args.concat(toArray(arguments)));
        };
    }

    function isCrossOriginURL(url) {
        var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);

        return parts && (
          parts[1] !== location.protocol ||
          parts[2] !== location.hostname ||
          parts[3] !== location.port
        );
    }

    function addTimestamp(url) {
        var timestamp = 'timestamp=' + (new Date()).getTime();

        return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
    }

    function getCrossOrigin(crossOrigin) {
        return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : '';
    }

    function getImageSize(image, callback) {
        var newImage;

        // Modern browsers (ignore Safari, #120 & #509)
        if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) {
            return callback(image.naturalWidth, image.naturalHeight);
        }

        // IE8: Don't use `new Image()` here (#319)
        newImage = document.createElement('img');

        newImage.onload = function () {
            callback(this.width, this.height);
        };

        newImage.src = image.src;
    }

    function getTransform(options) {
        var transforms = [];
        var rotate = options.rotate;
        var scaleX = options.scaleX;
        var scaleY = options.scaleY;

        // Rotate should come first before scale to match orientation transform
        if (isNumber(rotate) && rotate !== 0) {
            transforms.push('rotate(' + rotate + 'deg)');
        }

        if (isNumber(scaleX) && scaleX !== 1) {
            transforms.push('scaleX(' + scaleX + ')');
        }

        if (isNumber(scaleY) && scaleY !== 1) {
            transforms.push('scaleY(' + scaleY + ')');
        }

        return transforms.length ? transforms.join(' ') : 'none';
    }

    function getRotatedSizes(data, isReversed) {
        var deg = abs(data.degree) % 180;
        var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180;
        var sinArc = sin(arc);
        var cosArc = cos(arc);
        var width = data.width;
        var height = data.height;
        var aspectRatio = data.aspectRatio;
        var newWidth;
        var newHeight;

        if (!isReversed) {
            newWidth = width * cosArc + height * sinArc;
            newHeight = width * sinArc + height * cosArc;
        } else {
            newWidth = width / (cosArc + sinArc / aspectRatio);
            newHeight = newWidth / aspectRatio;
        }

        return {
            width: newWidth,
            height: newHeight
        };
    }

    function getSourceCanvas(image, data) {
        var canvas = $('<canvas>')[0];
        var context = canvas.getContext('2d');
        var dstX = 0;
        var dstY = 0;
        var dstWidth = data.naturalWidth;
        var dstHeight = data.naturalHeight;
        var rotate = data.rotate;
        var scaleX = data.scaleX;
        var scaleY = data.scaleY;
        var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1);
        var rotatable = isNumber(rotate) && rotate !== 0;
        var advanced = rotatable || scalable;
        var canvasWidth = dstWidth * abs(scaleX || 1);
        var canvasHeight = dstHeight * abs(scaleY || 1);
        var translateX;
        var translateY;
        var rotated;

        if (scalable) {
            translateX = canvasWidth / 2;
            translateY = canvasHeight / 2;
        }

        if (rotatable) {
            rotated = getRotatedSizes({
                width: canvasWidth,
                height: canvasHeight,
                degree: rotate
            });

            canvasWidth = rotated.width;
            canvasHeight = rotated.height;
            translateX = canvasWidth / 2;
            translateY = canvasHeight / 2;
        }

        canvas.width = canvasWidth;
        canvas.height = canvasHeight;

        if (advanced) {
            dstX = -dstWidth / 2;
            dstY = -dstHeight / 2;

            context.save();
            context.translate(translateX, translateY);
        }

        // Rotate should come first before scale as in the "getTransform" function
        if (rotatable) {
            context.rotate(rotate * Math.PI / 180);
        }

        if (scalable) {
            context.scale(scaleX, scaleY);
        }

        context.drawImage(image, floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));

        if (advanced) {
            context.restore();
        }

        return canvas;
    }

    function getTouchesCenter(touches) {
        var length = touches.length;
        var pageX = 0;
        var pageY = 0;

        if (length) {
            $.each(touches, function (i, touch) {
                pageX += touch.pageX;
                pageY += touch.pageY;
            });

            pageX /= length;
            pageY /= length;
        }

        return {
            pageX: pageX,
            pageY: pageY
        };
    }

    function getStringFromCharCode(dataView, start, length) {
        var str = '';
        var i;

        for (i = start, length += start; i < length; i++) {
            str += fromCharCode(dataView.getUint8(i));
        }

        return str;
    }

    function getOrientation(arrayBuffer) {
        var dataView = new DataView(arrayBuffer);
        var length = dataView.byteLength;
        var orientation;
        var exifIDCode;
        var tiffOffset;
        var firstIFDOffset;
        var littleEndian;
        var endianness;
        var app1Start;
        var ifdStart;
        var offset;
        var i;

        // Only handle JPEG image (start by 0xFFD8)
        if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
            offset = 2;

            while (offset < length) {
                if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
                    app1Start = offset;
                    break;
                }

                offset++;
            }
        }

        if (app1Start) {
            exifIDCode = app1Start + 4;
            tiffOffset = app1Start + 10;

            if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
                endianness = dataView.getUint16(tiffOffset);
                littleEndian = endianness === 0x4949;

                if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
                    if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
                        firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);

                        if (firstIFDOffset >= 0x00000008) {
                            ifdStart = tiffOffset + firstIFDOffset;
                        }
                    }
                }
            }
        }

        if (ifdStart) {
            length = dataView.getUint16(ifdStart, littleEndian);

            for (i = 0; i < length; i++) {
                offset = ifdStart + i * 12 + 2;

                if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {

                    // 8 is the offset of the current tag's value
                    offset += 8;

                    // Get the original orientation value
                    orientation = dataView.getUint16(offset, littleEndian);

                    // Override the orientation with its default value for Safari (#120)
                    if (IS_SAFARI_OR_UIWEBVIEW) {
                        dataView.setUint16(offset, 1, littleEndian);
                    }

                    break;
                }
            }
        }

        return orientation;
    }

    function dataURLToArrayBuffer(dataURL) {
        var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');
        var binary = atob(base64);
        var length = binary.length;
        var arrayBuffer = new ArrayBuffer(length);
        var dataView = new Uint8Array(arrayBuffer);
        var i;

        for (i = 0; i < length; i++) {
            dataView[i] = binary.charCodeAt(i);
        }

        return arrayBuffer;
    }

    // Only available for JPEG image
    function arrayBufferToDataURL(arrayBuffer) {
        var dataView = new Uint8Array(arrayBuffer);
        var length = dataView.length;
        var base64 = '';
        var i;

        for (i = 0; i < length; i++) {
            base64 += fromCharCode(dataView[i]);
        }

        return 'data:image/jpeg;base64,' + btoa(base64);
    }

    function Cropper(element, options) {
        this.$element = $(element);
        this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
        this.isLoaded = false;
        this.isBuilt = false;
        this.isCompleted = false;
        this.isRotated = false;
        this.isCropped = false;
        this.isDisabled = false;
        this.isReplaced = false;
        this.isLimited = false;
        this.wheeling = false;
        this.isImg = false;
        this.originalUrl = '';
        this.canvas = null;
        this.cropBox = null;
        this.init();
    }

    Cropper.prototype = {
        constructor: Cropper,

        init: function () {
            var $this = this.$element;
            var url;

            if ($this.is('img')) {
                this.isImg = true;

                // Should use `$.fn.attr` here. e.g.: "img/picture.jpg"
                this.originalUrl = url = $this.attr('src');

                // Stop when it's a blank image
                if (!url) {
                    return;
                }

                // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg"
                url = $this.prop('src');
            } else if ($this.is('canvas') && SUPPORT_CANVAS) {
                url = $this[0].toDataURL();
            }

            this.load(url);
        },

        // A shortcut for triggering custom events
        trigger: function (type, data) {
            var e = $.Event(type, data);

            this.$element.trigger(e);

            return e;
        },

        load: function (url) {
            var options = this.options;
            var $this = this.$element;
            var read;
            var xhr;

            if (!url) {
                return;
            }

            // Trigger build event first
            $this.one(EVENT_BUILD, options.build);

            if (this.trigger(EVENT_BUILD).isDefaultPrevented()) {
                return;
            }

            this.url = url;
            this.image = {};

            if (!options.checkOrientation || !ArrayBuffer) {
                return this.clone();
            }

            read = $.proxy(this.read, this);

            // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari
            if (REGEXP_DATA_URL.test(url)) {
                return REGEXP_DATA_URL_JPEG.test(url) ?
                  read(dataURLToArrayBuffer(url)) :
                  this.clone();
            }

            xhr = new XMLHttpRequest();

            xhr.onerror = xhr.onabort = $.proxy(function () {
                this.clone();
            }, this);

            xhr.onload = function () {
                read(this.response);
            };

            if (options.checkCrossOrigin && isCrossOriginURL(url) && $this.prop('crossOrigin')) {
                url = addTimestamp(url);
            }

            xhr.open('get', url);
            xhr.responseType = 'arraybuffer';
            xhr.send();
        },

        read: function (arrayBuffer) {
            var options = this.options;
            var orientation = getOrientation(arrayBuffer);
            var image = this.image;
            var rotate = 0;
            var scaleX = 1;
            var scaleY = 1;

            if (orientation > 1) {
                this.url = arrayBufferToDataURL(arrayBuffer);

                switch (orientation) {

                    // flip horizontal
                    case 2:
                        scaleX = -1;
                        break;

                        // rotate left 180�
                    case 3:
                        rotate = -180;
                        break;

                        // flip vertical
                    case 4:
                        scaleY = -1;
                        break;

                        // flip vertical + rotate right 90�
                    case 5:
                        rotate = 90;
                        scaleY = -1;
                        break;

                        // rotate right 90�
                    case 6:
                        rotate = 90;
                        break;

                        // flip horizontal + rotate right 90�
                    case 7:
                        rotate = 90;
                        scaleX = -1;
                        break;

                        // rotate left 90�
                    case 8:
                        rotate = -90;
                        break;
                }
            }

            if (options.rotatable) {
                image.rotate = rotate;
            }

            if (options.scalable) {
                image.scaleX = scaleX;
                image.scaleY = scaleY;
            }

            this.clone();
        },

        clone: function () {
            var options = this.options;
            var $this = this.$element;
            var url = this.url;
            var crossOrigin = '';
            var crossOriginUrl;
            var $clone;

            if (options.checkCrossOrigin && isCrossOriginURL(url)) {
                crossOrigin = $this.prop('crossOrigin');

                if (crossOrigin) {
                    crossOriginUrl = url;
                } else {
                    crossOrigin = 'anonymous';

                    // Bust cache (#148) when there is not a "crossOrigin" property
                    crossOriginUrl = addTimestamp(url);
                }
            }

            this.crossOrigin = crossOrigin;
            this.crossOriginUrl = crossOriginUrl;
            this.$clone = $clone = $('<img' + getCrossOrigin(crossOrigin) + ' src="' + (crossOriginUrl || url) + '">');

            if (this.isImg) {
                if ($this[0].complete) {
                    this.start();
                } else {
                    $this.one(EVENT_LOAD, $.proxy(this.start, this));
                }
            } else {
                $clone.
                  one(EVENT_LOAD, $.proxy(this.start, this)).
                  one(EVENT_ERROR, $.proxy(this.stop, this)).
                  addClass(CLASS_HIDE).
                  insertAfter($this);
            }
        },

        start: function () {
            var $image = this.$element;
            var $clone = this.$clone;

            if (!this.isImg) {
                $clone.off(EVENT_ERROR, this.stop);
                $image = $clone;
            }

            getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) {
                $.extend(this.image, {
                    naturalWidth: naturalWidth,
                    naturalHeight: naturalHeight,
                    aspectRatio: naturalWidth / naturalHeight
                });

                this.isLoaded = true;
                this.build();
            }, this));
        },

        stop: function () {
            this.$clone.remove();
            this.$clone = null;
        },

        build: function () {
            var options = this.options;
            var $this = this.$element;
            var $clone = this.$clone;
            var $cropper;
            var $cropBox;
            var $face;

            if (!this.isLoaded) {
                return;
            }

            // Unbuild first when replace
            if (this.isBuilt) {
                this.unbuild();
            }

            // Create cropper elements
            this.$container = $this.parent();
            this.$cropper = $cropper = $(Cropper.TEMPLATE);
            this.$canvas = $cropper.find('.cropper-canvas').append($clone);
            this.$dragBox = $cropper.find('.cropper-drag-box');
            this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
            this.$viewBox = $cropper.find('.cropper-view-box');
            this.$face = $face = $cropBox.find('.cropper-face');

            // Hide the original image
            $this.addClass(CLASS_HIDDEN).after($cropper);

            // Show the clone image if is hidden
            if (!this.isImg) {
                $clone.removeClass(CLASS_HIDE);
            }

            this.initPreview();
            this.bind();

            options.aspectRatio = max(0, options.aspectRatio) || NaN;
            options.viewMode = max(0, min(3, round(options.viewMode))) || 0;

            if (options.autoCrop) {
                this.isCropped = true;

                if (options.modal) {
                    this.$dragBox.addClass(CLASS_MODAL);
                }
            } else {
                $cropBox.addClass(CLASS_HIDDEN);
            }

            if (!options.guides) {
                $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
            }

            if (!options.center) {
                $cropBox.find('.cropper-center').addClass(CLASS_HIDDEN);
            }

            if (options.cropBoxMovable) {
                $face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL);
            }

            if (!options.highlight) {
                $face.addClass(CLASS_INVISIBLE);
            }

            if (options.background) {
                $cropper.addClass(CLASS_BG);
            }

            if (!options.cropBoxResizable) {
                $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
            }

            this.setDragMode(options.dragMode);
            this.render();
            this.isBuilt = true;
            this.setData(options.data);
            $this.one(EVENT_BUILT, options.built);

            // Trigger the built event asynchronously to keep `data('cropper')` is defined
            this.completing = setTimeout($.proxy(function () {
                this.trigger(EVENT_BUILT);
                this.trigger(EVENT_CROP, this.getData());
                this.isCompleted = true;
            }, this), 0);
        },

        unbuild: function () {
            if (!this.isBuilt) {
                return;
            }

            if (!this.isCompleted) {
                clearTimeout(this.completing);
            }

            this.isBuilt = false;
            this.isCompleted = false;
            this.initialImage = null;

            // Clear `initialCanvas` is necessary when replace
            this.initialCanvas = null;
            this.initialCropBox = null;
            this.container = null;
            this.canvas = null;

            // Clear `cropBox` is necessary when replace
            this.cropBox = null;
            this.unbind();

            this.resetPreview();
            this.$preview = null;

            this.$viewBox = null;
            this.$cropBox = null;
            this.$dragBox = null;
            this.$canvas = null;
            this.$container = null;

            this.$cropper.remove();
            this.$cropper = null;
        },

        render: function () {
            this.initContainer();
            this.initCanvas();
            this.initCropBox();

            this.renderCanvas();

            if (this.isCropped) {
                this.renderCropBox();
            }
        },

        initContainer: function () {
            var options = this.options;
            var $this = this.$element;
            var $container = this.$container;
            var $cropper = this.$cropper;

            $cropper.addClass(CLASS_HIDDEN);
            $this.removeClass(CLASS_HIDDEN);

            $cropper.css((this.container = {
                width: max($container.width(), num(options.minContainerWidth) || 200),
                height: max($container.height(), num(options.minContainerHeight) || 100)
            }));

            $this.addClass(CLASS_HIDDEN);
            $cropper.removeClass(CLASS_HIDDEN);
        },

        // Canvas (image wrapper)
        initCanvas: function () {
            var viewMode = this.options.viewMode;
            var container = this.container;
            var containerWidth = container.width;
            var containerHeight = container.height;
            var image = this.image;
            var imageNaturalWidth = image.naturalWidth;
            var imageNaturalHeight = image.naturalHeight;
            var is90Degree = abs(image.rotate) === 90;
            var naturalWidth = is90Degree ? imageNaturalHeight : imageNaturalWidth;
            var naturalHeight = is90Degree ? imageNaturalWidth : imageNaturalHeight;
            var aspectRatio = naturalWidth / naturalHeight;
            var canvasWidth = containerWidth;
            var canvasHeight = containerHeight;
            var canvas;

            if (containerHeight * aspectRatio > containerWidth) {
                if (viewMode === 3) {
                    canvasWidth = containerHeight * aspectRatio;
                } else {
                    canvasHeight = containerWidth / aspectRatio;
                }
            } else {
                if (viewMode === 3) {
                    canvasHeight = containerWidth / aspectRatio;
                } else {
                    canvasWidth = containerHeight * aspectRatio;
                }
            }

            canvas = {
                naturalWidth: naturalWidth,
                naturalHeight: naturalHeight,
                aspectRatio: aspectRatio,
                width: canvasWidth,
                height: canvasHeight
            };

            canvas.oldLeft = canvas.left = (containerWidth - canvasWidth) / 2;
            canvas.oldTop = canvas.top = (containerHeight - canvasHeight) / 2;

            this.canvas = canvas;
            this.isLimited = (viewMode === 1 || viewMode === 2);
            this.limitCanvas(true, true);
            this.initialImage = $.extend({}, image);
            this.initialCanvas = $.extend({}, canvas);
        },

        limitCanvas: function (isSizeLimited, isPositionLimited) {
            var options = this.options;
            var viewMode = options.viewMode;
            var container = this.container;
            var containerWidth = container.width;
            var containerHeight = container.height;
            var canvas = this.canvas;
            var aspectRatio = canvas.aspectRatio;
            var cropBox = this.cropBox;
            var isCropped = this.isCropped && cropBox;
            var minCanvasWidth;
            var minCanvasHeight;
            var newCanvasLeft;
            var newCanvasTop;

            if (isSizeLimited) {
                minCanvasWidth = num(options.minCanvasWidth) || 0;
                minCanvasHeight = num(options.minCanvasHeight) || 0;

                if (viewMode) {
                    if (viewMode > 1) {
                        minCanvasWidth = max(minCanvasWidth, containerWidth);
                        minCanvasHeight = max(minCanvasHeight, containerHeight);

                        if (viewMode === 3) {
                            if (minCanvasHeight * aspectRatio > minCanvasWidth) {
                                minCanvasWidth = minCanvasHeight * aspectRatio;
                            } else {
                                minCanvasHeight = minCanvasWidth / aspectRatio;
                            }
                        }
                    } else {
                        if (minCanvasWidth) {
                            minCanvasWidth = max(minCanvasWidth, isCropped ? cropBox.width : 0);
                        } else if (minCanvasHeight) {
                            minCanvasHeight = max(minCanvasHeight, isCropped ? cropBox.height : 0);
                        } else if (isCropped) {
                            minCanvasWidth = cropBox.width;
                            minCanvasHeight = cropBox.height;

                            if (minCanvasHeight * aspectRatio > minCanvasWidth) {
                                minCanvasWidth = minCanvasHeight * aspectRatio;
                            } else {
                                minCanvasHeight = minCanvasWidth / aspectRatio;
                            }
                        }
                    }
                }

                if (minCanvasWidth && minCanvasHeight) {
                    if (minCanvasHeight * aspectRatio > minCanvasWidth) {
                        minCanvasHeight = minCanvasWidth / aspectRatio;
                    } else {
                        minCanvasWidth = minCanvasHeight * aspectRatio;
                    }
                } else if (minCanvasWidth) {
                    minCanvasHeight = minCanvasWidth / aspectRatio;
                } else if (minCanvasHeight) {
                    minCanvasWidth = minCanvasHeight * aspectRatio;
                }

                canvas.minWidth = minCanvasWidth;
                canvas.minHeight = minCanvasHeight;
                canvas.maxWidth = Infinity;
                canvas.maxHeight = Infinity;
            }

            if (isPositionLimited) {
                if (viewMode) {
                    newCanvasLeft = containerWidth - canvas.width;
                    newCanvasTop = containerHeight - canvas.height;

                    canvas.minLeft = min(0, newCanvasLeft);
                    canvas.minTop = min(0, newCanvasTop);
                    canvas.maxLeft = max(0, newCanvasLeft);
                    canvas.maxTop = max(0, newCanvasTop);

                    if (isCropped && this.isLimited) {
                        canvas.minLeft = min(
                          cropBox.left,
                          cropBox.left + cropBox.width - canvas.width
                        );
                        canvas.minTop = min(
                          cropBox.top,
                          cropBox.top + cropBox.height - canvas.height
                        );
                        canvas.maxLeft = cropBox.left;
                        canvas.maxTop = cropBox.top;

                        if (viewMode === 2) {
                            if (canvas.width >= containerWidth) {
                                canvas.minLeft = min(0, newCanvasLeft);
                                canvas.maxLeft = max(0, newCanvasLeft);
                            }

                            if (canvas.height >= containerHeight) {
                                canvas.minTop = min(0, newCanvasTop);
                                canvas.maxTop = max(0, newCanvasTop);
                            }
                        }
                    }
                } else {
                    canvas.minLeft = -canvas.width;
                    canvas.minTop = -canvas.height;
                    canvas.maxLeft = containerWidth;
                    canvas.maxTop = containerHeight;
                }
            }
        },

        renderCanvas: function (isChanged) {
            var canvas = this.canvas;
            var image = this.image;
            var rotate = image.rotate;
            var naturalWidth = image.naturalWidth;
            var naturalHeight = image.naturalHeight;
            var aspectRatio;
            var rotated;

            if (this.isRotated) {
                this.isRotated = false;

                // Computes rotated sizes with image sizes
                rotated = getRotatedSizes({
                    width: image.width,
                    height: image.height,
                    degree: rotate
                });

                aspectRatio = rotated.width / rotated.height;

                if (aspectRatio !== canvas.aspectRatio) {
                    canvas.left -= (rotated.width - canvas.width) / 2;
                    canvas.top -= (rotated.height - canvas.height) / 2;
                    canvas.width = rotated.width;
                    canvas.height = rotated.height;
                    canvas.aspectRatio = aspectRatio;
                    canvas.naturalWidth = naturalWidth;
                    canvas.naturalHeight = naturalHeight;

                    // Computes rotated sizes with natural image sizes
                    if (rotate % 180) {
                        rotated = getRotatedSizes({
                            width: naturalWidth,
                            height: naturalHeight,
                            degree: rotate
                        });

                        canvas.naturalWidth = rotated.width;
                        canvas.naturalHeight = rotated.height;
                    }

                    this.limitCanvas(true, false);
                }
            }

            if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) {
                canvas.left = canvas.oldLeft;
            }

            if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) {
                canvas.top = canvas.oldTop;
            }

            canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth);
            canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight);

            this.limitCanvas(false, true);

            canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft);
            canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop);

            this.$canvas.css({
                width: canvas.width,
                height: canvas.height,
                left: canvas.left,
                top: canvas.top
            });

            this.renderImage();

            if (this.isCropped && this.isLimited) {
                this.limitCropBox(true, true);
            }

            if (isChanged) {
                this.output();
            }
        },

        renderImage: function (isChanged) {
            var canvas = this.canvas;
            var image = this.image;
            var reversed;

            if (image.rotate) {
                reversed = getRotatedSizes({
                    width: canvas.width,
                    height: canvas.height,
                    degree: image.rotate,
                    aspectRatio: image.aspectRatio
                }, true);
            }

            $.extend(image, reversed ? {
                width: reversed.width,
                height: reversed.height,
                left: (canvas.width - reversed.width) / 2,
                top: (canvas.height - reversed.height) / 2
            } : {
                width: canvas.width,
                height: canvas.height,
                left: 0,
                top: 0
            });

            this.$clone.css({
                width: image.width,
                height: image.height,
                marginLeft: image.left,
                marginTop: image.top,
                transform: getTransform(image)
            });

            if (isChanged) {
                this.output();
            }
        },

        initCropBox: function () {
            var options = this.options;
            var canvas = this.canvas;
            var aspectRatio = options.aspectRatio;
            var autoCropArea = num(options.autoCropArea) || 0.8;
            var cropBox = {
                width: canvas.width,
                height: canvas.height
            };

            if (aspectRatio) {
                if (canvas.height * aspectRatio > canvas.width) {
                    cropBox.height = cropBox.width / aspectRatio;
                } else {
                    cropBox.width = cropBox.height * aspectRatio;
                }
            }

            this.cropBox = cropBox;
            this.limitCropBox(true, true);

            // Initialize auto crop area
            cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
            cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);

            // The width of auto crop area must large than "minWidth", and the height too. (#164)
            cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea);
            cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea);
            cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2;
            cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2;

            this.initialCropBox = $.extend({}, cropBox);
        },

        limitCropBox: function (isSizeLimited, isPositionLimited) {
            var options = this.options;
            var aspectRatio = options.aspectRatio;
            var container = this.container;
            var containerWidth = container.width;
            var containerHeight = container.height;
            var canvas = this.canvas;
            var cropBox = this.cropBox;
            var isLimited = this.isLimited;
            var minCropBoxWidth;
            var minCropBoxHeight;
            var maxCropBoxWidth;
            var maxCropBoxHeight;

            if (isSizeLimited) {
                minCropBoxWidth = num(options.minCropBoxWidth) || 0;
                minCropBoxHeight = num(options.minCropBoxHeight) || 0;

                // The min/maxCropBoxWidth/Height must be less than containerWidth/Height
                minCropBoxWidth = min(minCropBoxWidth, containerWidth);
                minCropBoxHeight = min(minCropBoxHeight, containerHeight);
                maxCropBoxWidth = min(containerWidth, isLimited ? canvas.width : containerWidth);
                maxCropBoxHeight = min(containerHeight, isLimited ? canvas.height : containerHeight);

                if (aspectRatio) {
                    if (minCropBoxWidth && minCropBoxHeight) {
                        if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {
                            minCropBoxHeight = minCropBoxWidth / aspectRatio;
                        } else {
                            minCropBoxWidth = minCropBoxHeight * aspectRatio;
                        }
                    } else if (minCropBoxWidth) {
                        minCropBoxHeight = minCropBoxWidth / aspectRatio;
                    } else if (minCropBoxHeight) {
                        minCropBoxWidth = minCropBoxHeight * aspectRatio;
                    }

                    if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {
                        maxCropBoxHeight = maxCropBoxWidth / aspectRatio;
                    } else {
                        maxCropBoxWidth = maxCropBoxHeight * aspectRatio;
                    }
                }

                // The minWidth/Height must be less than maxWidth/Height
                cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth);
                cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight);
                cropBox.maxWidth = maxCropBoxWidth;
                cropBox.maxHeight = maxCropBoxHeight;
            }

            if (isPositionLimited) {
                if (isLimited) {
                    cropBox.minLeft = max(0, canvas.left);
                    cropBox.minTop = max(0, canvas.top);
                    cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
                    cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height;
                } else {
                    cropBox.minLeft = 0;
                    cropBox.minTop = 0;
                    cropBox.maxLeft = containerWidth - cropBox.width;
                    cropBox.maxTop = containerHeight - cropBox.height;
                }
            }
        },

        renderCropBox: function () {
            var options = this.options;
            var container = this.container;
            var containerWidth = container.width;
            var containerHeight = container.height;
            var cropBox = this.cropBox;

            if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
                cropBox.left = cropBox.oldLeft;
            }

            if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) {
                cropBox.top = cropBox.oldTop;
            }

            cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
            cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);

            this.limitCropBox(false, true);

            cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft);
            cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);

            if (options.movable && options.cropBoxMovable) {

                // Turn to move the canvas when the crop box is equal to the container
                this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL);
            }

            this.$cropBox.css({
                width: cropBox.width,
                height: cropBox.height,
                left: cropBox.left,
                top: cropBox.top
            });

            if (this.isCropped && this.isLimited) {
                this.limitCanvas(true, true);
            }

            if (!this.isDisabled) {
                this.output();
            }
        },

        output: function () {
            this.preview();

            if (this.isCompleted) {
                this.trigger(EVENT_CROP, this.getData());
            }
        },

        initPreview: function () {
            var crossOrigin = getCrossOrigin(this.crossOrigin);
            var url = crossOrigin ? this.crossOriginUrl : this.url;
            var $clone2;

            this.$preview = $(this.options.preview);
            this.$clone2 = $clone2 = $('<img' + crossOrigin + ' src="' + url + '">');
            this.$viewBox.html($clone2);
            this.$preview.each(function () {
                var $this = $(this);

                // Save the original size for recover
                $this.data(DATA_PREVIEW, {
                    width: $this.width(),
                    height: $this.height(),
                    html: $this.html()
                });

                /**
                 * Override img element styles
                 * Add `display:block` to avoid margin top issue
                 * (Occur only when margin-top <= -height)
                 */
                $this.html(
                  '<img' + crossOrigin + ' src="' + url + '" style="' +
                  'display:block;width:100%;height:auto;' +
                  'min-width:0!important;min-height:0!important;' +
                  'max-width:none!important;max-height:none!important;' +
                  'image-orientation:0deg!important;">'
                );
            });
        },

        resetPreview: function () {
            this.$preview.each(function () {
                var $this = $(this);
                var data = $this.data(DATA_PREVIEW);

                $this.css({
                    width: data.width,
                    height: data.height
                }).html(data.html).removeData(DATA_PREVIEW);
            });
        },

        preview: function () {
            var image = this.image;
            var canvas = this.canvas;
            var cropBox = this.cropBox;
            var cropBoxWidth = cropBox.width;
            var cropBoxHeight = cropBox.height;
            var width = image.width;
            var height = image.height;
            var left = cropBox.left - canvas.left - image.left;
            var top = cropBox.top - canvas.top - image.top;

            if (!this.isCropped || this.isDisabled) {
                return;
            }

            this.$clone2.css({
                width: width,
                height: height,
                marginLeft: -left,
                marginTop: -top,
                transform: getTransform(image)
            });

            this.$preview.each(function () {
                var $this = $(this);
                var data = $this.data(DATA_PREVIEW);
                var originalWidth = data.width;
                var originalHeight = data.height;
                var newWidth = originalWidth;
                var newHeight = originalHeight;
                var ratio = 1;

                if (cropBoxWidth) {
                    ratio = originalWidth / cropBoxWidth;
                    newHeight = cropBoxHeight * ratio;
                }

                if (cropBoxHeight && newHeight > originalHeight) {
                    ratio = originalHeight / cropBoxHeight;
                    newWidth = cropBoxWidth * ratio;
                    newHeight = originalHeight;
                }

                $this.css({
                    width: newWidth,
                    height: newHeight
                }).find('img').css({
                    width: width * ratio,
                    height: height * ratio,
                    marginLeft: -left * ratio,
                    marginTop: -top * ratio,
                    transform: getTransform(image)
                });
            });
        },

        bind: function () {
            var options = this.options;
            var $this = this.$element;
            var $cropper = this.$cropper;

            if ($.isFunction(options.cropstart)) {
                $this.on(EVENT_CROP_START, options.cropstart);
            }

            if ($.isFunction(options.cropmove)) {
                $this.on(EVENT_CROP_MOVE, options.cropmove);
            }

            if ($.isFunction(options.cropend)) {
                $this.on(EVENT_CROP_END, options.cropend);
            }

            if ($.isFunction(options.crop)) {
                $this.on(EVENT_CROP, options.crop);
            }

            if ($.isFunction(options.zoom)) {
                $this.on(EVENT_ZOOM, options.zoom);
            }

            $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this));

            if (options.zoomable && options.zoomOnWheel) {
                $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
            }

            if (options.toggleDragModeOnDblclick) {
                $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
            }

            $document.
              on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))).
              on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this)));

            if (options.responsive) {
                $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
            }
        },

        unbind: function () {
            var options = this.options;
            var $this = this.$element;
            var $cropper = this.$cropper;

            if ($.isFunction(options.cropstart)) {
                $this.off(EVENT_CROP_START, options.cropstart);
            }

            if ($.isFunction(options.cropmove)) {
                $this.off(EVENT_CROP_MOVE, options.cropmove);
            }

            if ($.isFunction(options.cropend)) {
                $this.off(EVENT_CROP_END, options.cropend);
            }

            if ($.isFunction(options.crop)) {
                $this.off(EVENT_CROP, options.crop);
            }

            if ($.isFunction(options.zoom)) {
                $this.off(EVENT_ZOOM, options.zoom);
            }

            $cropper.off(EVENT_MOUSE_DOWN, this.cropStart);

            if (options.zoomable && options.zoomOnWheel) {
                $cropper.off(EVENT_WHEEL, this.wheel);
            }

            if (options.toggleDragModeOnDblclick) {
                $cropper.off(EVENT_DBLCLICK, this.dblclick);
            }

            $document.
              off(EVENT_MOUSE_MOVE, this._cropMove).
              off(EVENT_MOUSE_UP, this._cropEnd);

            if (options.responsive) {
                $window.off(EVENT_RESIZE, this._resize);
            }
        },

        resize: function () {
            var restore = this.options.restore;
            var $container = this.$container;
            var container = this.container;
            var canvasData;
            var cropBoxData;
            var ratio;

            // Check `container` is necessary for IE8
            if (this.isDisabled || !container) {
                return;
            }

            ratio = $container.width() / container.width;

            // Resize when width changed or height changed
            if (ratio !== 1 || $container.height() !== container.height) {
                if (restore) {
                    canvasData = this.getCanvasData();
                    cropBoxData = this.getCropBoxData();
                }

                this.render();

                if (restore) {
                    this.setCanvasData($.each(canvasData, function (i, n) {
                        canvasData[i] = n * ratio;
                    }));
                    this.setCropBoxData($.each(cropBoxData, function (i, n) {
                        cropBoxData[i] = n * ratio;
                    }));
                }
            }
        },

        dblclick: function () {
            if (this.isDisabled) {
                return;
            }

            if (this.$dragBox.hasClass(CLASS_CROP)) {
                this.setDragMode(ACTION_MOVE);
            } else {
                this.setDragMode(ACTION_CROP);
            }
        },

        wheel: function (event) {
            var e = event.originalEvent || event;
            var ratio = num(this.options.wheelZoomRatio) || 0.1;
            var delta = 1;

            if (this.isDisabled) {
                return;
            }

            event.preventDefault();

            // Limit wheel speed to prevent zoom too fast
            if (this.wheeling) {
                return;
            }

            this.wheeling = true;

            setTimeout($.proxy(function () {
                this.wheeling = false;
            }, this), 50);

            if (e.deltaY) {
                delta = e.deltaY > 0 ? 1 : -1;
            } else if (e.wheelDelta) {
                delta = -e.wheelDelta / 120;
            } else if (e.detail) {
                delta = e.detail > 0 ? 1 : -1;
            }

            this.zoom(-delta * ratio, event);
        },

        cropStart: function (event) {
            var options = this.options;
            var originalEvent = event.originalEvent;
            var touches = originalEvent && originalEvent.touches;
            var e = event;
            var touchesLength;
            var action;

            if (this.isDisabled) {
                return;
            }

            if (touches) {
                touchesLength = touches.length;

                if (touchesLength > 1) {
                    if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
                        e = touches[1];
                        this.startX2 = e.pageX;
                        this.startY2 = e.pageY;
                        action = ACTION_ZOOM;
                    } else {
                        return;
                    }
                }

                e = touches[0];
            }

            action = action || $(e.target).data(DATA_ACTION);

            if (REGEXP_ACTIONS.test(action)) {
                if (this.trigger(EVENT_CROP_START, {
                    originalEvent: originalEvent,
                    action: action
                }).isDefaultPrevented()) {
                    return;
                }

                event.preventDefault();

                this.action = action;
                this.cropping = false;

                // IE8  has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
                // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
                this.startX = e.pageX || originalEvent && originalEvent.pageX;
                this.startY = e.pageY || originalEvent && originalEvent.pageY;

                if (action === ACTION_CROP) {
                    this.cropping = true;
                    this.$dragBox.addClass(CLASS_MODAL);
                }
            }
        },

        cropMove: function (event) {
            var options = this.options;
            var originalEvent = event.originalEvent;
            var touches = originalEvent && originalEvent.touches;
            var e = event;
            var action = this.action;
            var touchesLength;

            if (this.isDisabled) {
                return;
            }

            if (touches) {
                touchesLength = touches.length;

                if (touchesLength > 1) {
                    if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
                        e = touches[1];
                        this.endX2 = e.pageX;
                        this.endY2 = e.pageY;
                    } else {
                        return;
                    }
                }

                e = touches[0];
            }

            if (action) {
                if (this.trigger(EVENT_CROP_MOVE, {
                    originalEvent: originalEvent,
                    action: action
                }).isDefaultPrevented()) {
                    return;
                }

                event.preventDefault();

                this.endX = e.pageX || originalEvent && originalEvent.pageX;
                this.endY = e.pageY || originalEvent && originalEvent.pageY;

                this.change(e.shiftKey, action === ACTION_ZOOM ? event : null);
            }
        },

        cropEnd: function (event) {
            var originalEvent = event.originalEvent;
            var action = this.action;

            if (this.isDisabled) {
                return;
            }

            if (action) {
                event.preventDefault();

                if (this.cropping) {
                    this.cropping = false;
                    this.$dragBox.toggleClass(CLASS_MODAL, this.isCropped && this.options.modal);
                }

                this.action = '';

                this.trigger(EVENT_CROP_END, {
                    originalEvent: originalEvent,
                    action: action
                });
            }
        },

        change: function (shiftKey, event) {
            var options = this.options;
            var aspectRatio = options.aspectRatio;
            var action = this.action;
            var container = this.container;
            var canvas = this.canvas;
            var cropBox = this.cropBox;
            var width = cropBox.width;
            var height = cropBox.height;
            var left = cropBox.left;
            var top = cropBox.top;
            var right = left + width;
            var bottom = top + height;
            var minLeft = 0;
            var minTop = 0;
            var maxWidth = container.width;
            var maxHeight = container.height;
            var renderable = true;
            var offset;
            var range;

            // Locking aspect ratio in "free mode" by holding shift key (#259)
            if (!aspectRatio && shiftKey) {
                aspectRatio = width && height ? width / height : 1;
            }

            if (this.isLimited) {
                minLeft = cropBox.minLeft;
                minTop = cropBox.minTop;
                maxWidth = minLeft + min(container.width, canvas.width, canvas.left + canvas.width);
                maxHeight = minTop + min(container.height, canvas.height, canvas.top + canvas.height);
            }

            range = {
                x: this.endX - this.startX,
                y: this.endY - this.startY
            };

            if (aspectRatio) {
                range.X = range.y * aspectRatio;
                range.Y = range.x / aspectRatio;
            }

            switch (action) {
                // Move crop box
                case ACTION_ALL:
                    left += range.x;
                    top += range.y;
                    break;

                    // Resize crop box
                case ACTION_EAST:
                    if (range.x >= 0 && (right >= maxWidth || aspectRatio &&
                      (top <= minTop || bottom >= maxHeight))) {

                        renderable = false;
                        break;
                    }

                    width += range.x;

                    if (aspectRatio) {
                        height = width / aspectRatio;
                        top -= range.Y / 2;
                    }

                    if (width < 0) {
                        action = ACTION_WEST;
                        width = 0;
                    }

                    break;

                case ACTION_NORTH:
                    if (range.y <= 0 && (top <= minTop || aspectRatio &&
                      (left <= minLeft || right >= maxWidth))) {

                        renderable = false;
                        break;
                    }

                    height -= range.y;
                    top += range.y;

                    if (aspectRatio) {
                        width = height * aspectRatio;
                        left += range.X / 2;
                    }

                    if (height < 0) {
                        action = ACTION_SOUTH;
                        height = 0;
                    }

                    break;

                case ACTION_WEST:
                    if (range.x <= 0 && (left <= minLeft || aspectRatio &&
                      (top <= minTop || bottom >= maxHeight))) {

                        renderable = false;
                        break;
                    }

                    width -= range.x;
                    left += range.x;

                    if (aspectRatio) {
                        height = width / aspectRatio;
                        top += range.Y / 2;
                    }

                    if (width < 0) {
                        action = ACTION_EAST;
                        width = 0;
                    }

                    break;

                case ACTION_SOUTH:
                    if (range.y >= 0 && (bottom >= maxHeight || aspectRatio &&
                      (left <= minLeft || right >= maxWidth))) {

                        renderable = false;
                        break;
                    }

                    height += range.y;

                    if (aspectRatio) {
                        width = height * aspectRatio;
                        left -= range.X / 2;
                    }

                    if (height < 0) {
                        action = ACTION_NORTH;
                        height = 0;
                    }

                    break;

                case ACTION_NORTH_EAST:
                    if (aspectRatio) {
                        if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
                            renderable = false;
                            break;
                        }

                        height -= range.y;
                        top += range.y;
                        width = height * aspectRatio;
                    } else {
                        if (range.x >= 0) {
                            if (right < maxWidth) {
                                width += range.x;
                            } else if (range.y <= 0 && top <= minTop) {
                                renderable = false;
                            }
                        } else {
                            width += range.x;
                        }

                        if (range.y <= 0) {
                            if (top > minTop) {
                                height -= range.y;
                                top += range.y;
                            }
                        } else {
                            height -= range.y;
                            top += range.y;
                        }
                    }

                    if (width < 0 && height < 0) {
                        action = ACTION_SOUTH_WEST;
                        height = 0;
                        width = 0;
                    } else if (width < 0) {
                        action = ACTION_NORTH_WEST;
                        width = 0;
                    } else if (height < 0) {
                        action = ACTION_SOUTH_EAST;
                        height = 0;
                    }

                    break;

                case ACTION_NORTH_WEST:
                    if (aspectRatio) {
                        if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
                            renderable = false;
                            break;
                        }

                        height -= range.y;
                        top += range.y;
                        width = height * aspectRatio;
                        left += range.X;
                    } else {
                        if (range.x <= 0) {
                            if (left > minLeft) {
                                width -= range.x;
                                left += range.x;
                            } else if (range.y <= 0 && top <= minTop) {
                                renderable = false;
                            }
                        } else {
                            width -= range.x;
                            left += range.x;
                        }

                        if (range.y <= 0) {
                            if (top > minTop) {
                                height -= range.y;
                                top += range.y;
                            }
                        } else {
                            height -= range.y;
                            top += range.y;
                        }
                    }

                    if (width < 0 && height < 0) {
                        action = ACTION_SOUTH_EAST;
                        height = 0;
                        width = 0;
                    } else if (width < 0) {
                        action = ACTION_NORTH_EAST;
                        width = 0;
                    } else if (height < 0) {
                        action = ACTION_SOUTH_WEST;
                        height = 0;
                    }

                    break;

                case ACTION_SOUTH_WEST:
                    if (aspectRatio) {
                        if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
                            renderable = false;
                            break;
                        }

                        width -= range.x;
                        left += range.x;
                        height = width / aspectRatio;
                    } else {
                        if (range.x <= 0) {
                            if (left > minLeft) {
                                width -= range.x;
                                left += range.x;
                            } else if (range.y >= 0 && bottom >= maxHeight) {
                                renderable = false;
                            }
                        } else {
                            width -= range.x;
                            left += range.x;
                        }

                        if (range.y >= 0) {
                            if (bottom < maxHeight) {
                                height += range.y;
                            }
                        } else {
                            height += range.y;
                        }
                    }

                    if (width < 0 && height < 0) {
                        action = ACTION_NORTH_EAST;
                        height = 0;
                        width = 0;
                    } else if (width < 0) {
                        action = ACTION_SOUTH_EAST;
                        width = 0;
                    } else if (height < 0) {
                        action = ACTION_NORTH_WEST;
                        height = 0;
                    }

                    break;

                case ACTION_SOUTH_EAST:
                    if (aspectRatio) {
                        if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
                            renderable = false;
                            break;
                        }

                        width += range.x;
                        height = width / aspectRatio;
                    } else {
                        if (range.x >= 0) {
                            if (right < maxWidth) {
                                width += range.x;
                            } else if (range.y >= 0 && bottom >= maxHeight) {
                                renderable = false;
                            }
                        } else {
                            width += range.x;
                        }

                        if (range.y >= 0) {
                            if (bottom < maxHeight) {
                                height += range.y;
                            }
                        } else {
                            height += range.y;
                        }
                    }

                    if (width < 0 && height < 0) {
                        action = ACTION_NORTH_WEST;
                        height = 0;
                        width = 0;
                    } else if (width < 0) {
                        action = ACTION_SOUTH_WEST;
                        width = 0;
                    } else if (height < 0) {
                        action = ACTION_NORTH_EAST;
                        height = 0;
                    }

                    break;

                    // Move canvas
                case ACTION_MOVE:
                    this.move(range.x, range.y);
                    renderable = false;
                    break;

                    // Zoom canvas
                case ACTION_ZOOM:
                    this.zoom((function (x1, y1, x2, y2) {
                        var z1 = sqrt(x1 * x1 + y1 * y1);
                        var z2 = sqrt(x2 * x2 + y2 * y2);

                        return (z2 - z1) / z1;
                    })(
                      abs(this.startX - this.startX2),
                      abs(this.startY - this.startY2),
                      abs(this.endX - this.endX2),
                      abs(this.endY - this.endY2)
                    ), event);
                    this.startX2 = this.endX2;
                    this.startY2 = this.endY2;
                    renderable = false;
                    break;

                    // Create crop box
                case ACTION_CROP:
                    if (!range.x || !range.y) {
                        renderable = false;
                        break;
                    }

                    offset = this.$cropper.offset();
                    left = this.startX - offset.left;
                    top = this.startY - offset.top;
                    width = cropBox.minWidth;
                    height = cropBox.minHeight;

                    if (range.x > 0) {
                        action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;
                    } else if (range.x < 0) {
                        left -= width;
                        action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;
                    }

                    if (range.y < 0) {
                        top -= height;
                    }

                    // Show the crop box if is hidden
                    if (!this.isCropped) {
                        this.$cropBox.removeClass(CLASS_HIDDEN);
                        this.isCropped = true;

                        if (this.isLimited) {
                            this.limitCropBox(true, true);
                        }
                    }

                    break;

                    // No default
            }

            if (renderable) {
                cropBox.width = width;
                cropBox.height = height;
                cropBox.left = left;
                cropBox.top = top;
                this.action = action;

                this.renderCropBox();
            }

            // Override
            this.startX = this.endX;
            this.startY = this.endY;
        },

        // Show the crop box manually
        crop: function () {
            if (!this.isBuilt || this.isDisabled) {
                return;
            }

            if (!this.isCropped) {
                this.isCropped = true;
                this.limitCropBox(true, true);

                if (this.options.modal) {
                    this.$dragBox.addClass(CLASS_MODAL);
                }

                this.$cropBox.removeClass(CLASS_HIDDEN);
            }

            this.setCropBoxData(this.initialCropBox);
        },

        // Reset the image and crop box to their initial states
        reset: function () {
            if (!this.isBuilt || this.isDisabled) {
                return;
            }

            this.image = $.extend({}, this.initialImage);
            this.canvas = $.extend({}, this.initialCanvas);
            this.cropBox = $.extend({}, this.initialCropBox);

            this.renderCanvas();

            if (this.isCropped) {
                this.renderCropBox();
            }
        },

        // Clear the crop box
        clear: function () {
            if (!this.isCropped || this.isDisabled) {
                return;
            }

            $.extend(this.cropBox, {
                left: 0,
                top: 0,
                width: 0,
                height: 0
            });

            this.isCropped = false;
            this.renderCropBox();

            this.limitCanvas(true, true);

            // Render canvas after crop box rendered
            this.renderCanvas();

            this.$dragBox.removeClass(CLASS_MODAL);
            this.$cropBox.addClass(CLASS_HIDDEN);
        },

        /**
         * Replace the image's src and rebuild the cropper
         *
         * @param {String} url
         * @param {Boolean} onlyColorChanged (optional)
         */
        replace: function (url, onlyColorChanged) {
            if (!this.isDisabled && url) {
                if (this.isImg) {
                    this.$element.attr('src', url);
                }

                if (onlyColorChanged) {
                    this.url = url;
                    this.$clone.attr('src', url);

                    if (this.isBuilt) {
                        this.$preview.find('img').add(this.$clone2).attr('src', url);
                    }
                } else {
                    if (this.isImg) {
                        this.isReplaced = true;
                    }

                    // Clear previous data
                    this.options.data = null;
                    this.load(url);
                }
            }
        },

        // Enable (unfreeze) the cropper
        enable: function () {
            if (this.isBuilt) {
                this.isDisabled = false;
                this.$cropper.removeClass(CLASS_DISABLED);
            }
        },

        // Disable (freeze) the cropper
        disable: function () {
            if (this.isBuilt) {
                this.isDisabled = true;
                this.$cropper.addClass(CLASS_DISABLED);
            }
        },

        // Destroy the cropper and remove the instance from the image
        destroy: function () {
            var $this = this.$element;

            if (this.isLoaded) {
                if (this.isImg && this.isReplaced) {
                    $this.attr('src', this.originalUrl);
                }

                this.unbuild();
                $this.removeClass(CLASS_HIDDEN);
            } else {
                if (this.isImg) {
                    $this.off(EVENT_LOAD, this.start);
                } else if (this.$clone) {
                    this.$clone.remove();
                }
            }

            $this.removeData(NAMESPACE);
        },

        /**
         * Move the canvas with relative offsets
         *
         * @param {Number} offsetX
         * @param {Number} offsetY (optional)
         */
        move: function (offsetX, offsetY) {
            var canvas = this.canvas;

            this.moveTo(
              isUndefined(offsetX) ? offsetX : canvas.left + num(offsetX),
              isUndefined(offsetY) ? offsetY : canvas.top + num(offsetY)
            );
        },

        /**
         * Move the canvas to an absolute point
         *
         * @param {Number} x
         * @param {Number} y (optional)
         */
        moveTo: function (x, y) {
            var canvas = this.canvas;
            var isChanged = false;

            // If "y" is not present, its default value is "x"
            if (isUndefined(y)) {
                y = x;
            }

            x = num(x);
            y = num(y);

            if (this.isBuilt && !this.isDisabled && this.options.movable) {
                if (isNumber(x)) {
                    canvas.left = x;
                    isChanged = true;
                }

                if (isNumber(y)) {
                    canvas.top = y;
                    isChanged = true;
                }

                if (isChanged) {
                    this.renderCanvas(true);
                }
            }
        },

        /**
         * Zoom the canvas with a relative ratio
         *
         * @param {Number} ratio
         * @param {jQuery Event} _event (private)
         */
        zoom: function (ratio, _event) {
            var canvas = this.canvas;

            ratio = num(ratio);

            if (ratio < 0) {
                ratio = 1 / (1 - ratio);
            } else {
                ratio = 1 + ratio;
            }

            this.zoomTo(canvas.width * ratio / canvas.naturalWidth, _event);
        },

        /**
         * Zoom the canvas to an absolute ratio
         *
         * @param {Number} ratio
         * @param {jQuery Event} _event (private)
         */
        zoomTo: function (ratio, _event) {
            var options = this.options;
            var canvas = this.canvas;
            var width = canvas.width;
            var height = canvas.height;
            var naturalWidth = canvas.naturalWidth;
            var naturalHeight = canvas.naturalHeight;
            var originalEvent;
            var newWidth;
            var newHeight;
            var offset;
            var center;

            ratio = num(ratio);

            if (ratio >= 0 && this.isBuilt && !this.isDisabled && options.zoomable) {
                newWidth = naturalWidth * ratio;
                newHeight = naturalHeight * ratio;

                if (_event) {
                    originalEvent = _event.originalEvent;
                }

                if (this.trigger(EVENT_ZOOM, {
                    originalEvent: originalEvent,
                    oldRatio: width / naturalWidth,
                    ratio: newWidth / naturalWidth
                }).isDefaultPrevented()) {
                    return;
                }

                if (originalEvent) {
                    offset = this.$cropper.offset();
                    center = originalEvent.touches ? getTouchesCenter(originalEvent.touches) : {
                        pageX: _event.pageX || originalEvent.pageX || 0,
                        pageY: _event.pageY || originalEvent.pageY || 0
                    };

                    // Zoom from the triggering point of the event
                    canvas.left -= (newWidth - width) * (
                      ((center.pageX - offset.left) - canvas.left) / width
                    );
                    canvas.top -= (newHeight - height) * (
                      ((center.pageY - offset.top) - canvas.top) / height
                    );
                } else {

                    // Zoom from the center of the canvas
                    canvas.left -= (newWidth - width) / 2;
                    canvas.top -= (newHeight - height) / 2;
                }

                canvas.width = newWidth;
                canvas.height = newHeight;
                this.renderCanvas(true);
            }
        },

        /**
         * Rotate the canvas with a relative degree
         *
         * @param {Number} degree
         */
        rotate: function (degree) {
            this.rotateTo((this.image.rotate || 0) + num(degree));
        },

        /**
         * Rotate the canvas to an absolute degree
         * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate()
         *
         * @param {Number} degree
         */
        rotateTo: function (degree) {
            degree = num(degree);

            if (isNumber(degree) && this.isBuilt && !this.isDisabled && this.options.rotatable) {
                this.image.rotate = degree % 360;
                this.isRotated = true;
                this.renderCanvas(true);
            }
        },

        /**
         * Scale the image
         * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale()
         *
         * @param {Number} scaleX
         * @param {Number} scaleY (optional)
         */
        scale: function (scaleX, scaleY) {
            var image = this.image;
            var isChanged = false;

            // If "scaleY" is not present, its default value is "scaleX"
            if (isUndefined(scaleY)) {
                scaleY = scaleX;
            }

            scaleX = num(scaleX);
            scaleY = num(scaleY);

            if (this.isBuilt && !this.isDisabled && this.options.scalable) {
                if (isNumber(scaleX)) {
                    image.scaleX = scaleX;
                    isChanged = true;
                }

                if (isNumber(scaleY)) {
                    image.scaleY = scaleY;
                    isChanged = true;
                }

                if (isChanged) {
                    this.renderImage(true);
                }
            }
        },

        /**
         * Scale the abscissa of the image
         *
         * @param {Number} scaleX
         */
        scaleX: function (scaleX) {
            var scaleY = this.image.scaleY;

            this.scale(scaleX, isNumber(scaleY) ? scaleY : 1);
        },

        /**
         * Scale the ordinate of the image
         *
         * @param {Number} scaleY
         */
        scaleY: function (scaleY) {
            var scaleX = this.image.scaleX;

            this.scale(isNumber(scaleX) ? scaleX : 1, scaleY);
        },

        /**
         * Get the cropped area position and size data (base on the original image)
         *
         * @param {Boolean} isRounded (optional)
         * @return {Object} data
         */
        getData: function (isRounded) {
            var options = this.options;
            var image = this.image;
            var canvas = this.canvas;
            var cropBox = this.cropBox;
            var ratio;
            var data;

            if (this.isBuilt && this.isCropped) {
                data = {
                    x: cropBox.left - canvas.left,
                    y: cropBox.top - canvas.top,
                    width: cropBox.width,
                    height: cropBox.height
                };

                ratio = image.width / image.naturalWidth;

                $.each(data, function (i, n) {
                    n = n / ratio;
                    data[i] = isRounded ? round(n) : n;
                });

            } else {
                data = {
                    x: 0,
                    y: 0,
                    width: 0,
                    height: 0
                };
            }

            if (options.rotatable) {
                data.rotate = image.rotate || 0;
            }

            if (options.scalable) {
                data.scaleX = image.scaleX || 1;
                data.scaleY = image.scaleY || 1;
            }

            return data;
        },

        /**
         * Set the cropped area position and size with new data
         *
         * @param {Object} data
         */
        setData: function (data) {
            var options = this.options;
            var image = this.image;
            var canvas = this.canvas;
            var cropBoxData = {};
            var isRotated;
            var isScaled;
            var ratio;

            if ($.isFunction(data)) {
                data = data.call(this.element);
            }

            if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
                if (options.rotatable) {
                    if (isNumber(data.rotate) && data.rotate !== image.rotate) {
                        image.rotate = data.rotate;
                        this.isRotated = isRotated = true;
                    }
                }

                if (options.scalable) {
                    if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) {
                        image.scaleX = data.scaleX;
                        isScaled = true;
                    }

                    if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) {
                        image.scaleY = data.scaleY;
                        isScaled = true;
                    }
                }

                if (isRotated) {
                    this.renderCanvas();
                } else if (isScaled) {
                    this.renderImage();
                }

                ratio = image.width / image.naturalWidth;

                if (isNumber(data.x)) {
                    cropBoxData.left = data.x * ratio + canvas.left;
                }

                if (isNumber(data.y)) {
                    cropBoxData.top = data.y * ratio + canvas.top;
                }

                if (isNumber(data.width)) {
                    cropBoxData.width = data.width * ratio;
                }

                if (isNumber(data.height)) {
                    cropBoxData.height = data.height * ratio;
                }

                this.setCropBoxData(cropBoxData);
            }
        },

        /**
         * Get the container size data
         *
         * @return {Object} data
         */
        getContainerData: function () {
            return this.isBuilt ? this.container : {};
        },

        /**
         * Get the image position and size data
         *
         * @return {Object} data
         */
        getImageData: function () {
            return this.isLoaded ? this.image : {};
        },

        /**
         * Get the canvas position and size data
         *
         * @return {Object} data
         */
        getCanvasData: function () {
            var canvas = this.canvas;
            var data = {};

            if (this.isBuilt) {
                $.each([
                  'left',
                  'top',
                  'width',
                  'height',
                  'naturalWidth',
                  'naturalHeight'
                ], function (i, n) {
                    data[n] = canvas[n];
                });
            }

            return data;
        },

        /**
         * Set the canvas position and size with new data
         *
         * @param {Object} data
         */
        setCanvasData: function (data) {
            var canvas = this.canvas;
            var aspectRatio = canvas.aspectRatio;

            if ($.isFunction(data)) {
                data = data.call(this.$element);
            }

            if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
                if (isNumber(data.left)) {
                    canvas.left = data.left;
                }

                if (isNumber(data.top)) {
                    canvas.top = data.top;
                }

                if (isNumber(data.width)) {
                    canvas.width = data.width;
                    canvas.height = data.width / aspectRatio;
                } else if (isNumber(data.height)) {
                    canvas.height = data.height;
                    canvas.width = data.height * aspectRatio;
                }

                this.renderCanvas(true);
            }
        },

        /**
         * Get the crop box position and size data
         *
         * @return {Object} data
         */
        getCropBoxData: function () {
            var cropBox = this.cropBox;
            var data;

            if (this.isBuilt && this.isCropped) {
                data = {
                    left: cropBox.left,
                    top: cropBox.top,
                    width: cropBox.width,
                    height: cropBox.height
                };
            }

            return data || {};
        },

        /**
         * Set the crop box position and size with new data
         *
         * @param {Object} data
         */
        setCropBoxData: function (data) {
            var cropBox = this.cropBox;
            var aspectRatio = this.options.aspectRatio;
            var isWidthChanged;
            var isHeightChanged;

            if ($.isFunction(data)) {
                data = data.call(this.$element);
            }

            if (this.isBuilt && this.isCropped && !this.isDisabled && $.isPlainObject(data)) {

                if (isNumber(data.left)) {
                    cropBox.left = data.left;
                }

                if (isNumber(data.top)) {
                    cropBox.top = data.top;
                }

                if (isNumber(data.width)) {
                    isWidthChanged = true;
                    cropBox.width = data.width;
                }

                if (isNumber(data.height)) {
                    isHeightChanged = true;
                    cropBox.height = data.height;
                }

                if (aspectRatio) {
                    if (isWidthChanged) {
                        cropBox.height = cropBox.width / aspectRatio;
                    } else if (isHeightChanged) {
                        cropBox.width = cropBox.height * aspectRatio;
                    }
                }

                this.renderCropBox();
            }
        },

        /**
         * Get a canvas drawn the cropped image
         *
         * @param {Object} options (optional)
         * @return {HTMLCanvasElement} canvas
         */
        getCroppedCanvas: function (options) {
            var originalWidth;
            var originalHeight;
            var canvasWidth;
            var canvasHeight;
            var scaledWidth;
            var scaledHeight;
            var scaledRatio;
            var aspectRatio;
            var canvas;
            var context;
            var data;

            if (!this.isBuilt || !SUPPORT_CANVAS) {
                return;
            }

            if (!this.isCropped) {
                return getSourceCanvas(this.$clone[0], this.image);
            }

            if (!$.isPlainObject(options)) {
                options = {};
            }

            data = this.getData();
            originalWidth = data.width;
            originalHeight = data.height;
            aspectRatio = originalWidth / originalHeight;

            if ($.isPlainObject(options)) {
                scaledWidth = options.width;
                scaledHeight = options.height;

                if (scaledWidth) {
                    scaledHeight = scaledWidth / aspectRatio;
                    scaledRatio = scaledWidth / originalWidth;
                } else if (scaledHeight) {
                    scaledWidth = scaledHeight * aspectRatio;
                    scaledRatio = scaledHeight / originalHeight;
                }
            }

            // The canvas element will use `Math.floor` on a float number, so floor first
            canvasWidth = floor(scaledWidth || originalWidth);
            canvasHeight = floor(scaledHeight || originalHeight);

            canvas = $('<canvas>')[0];
            canvas.width = canvasWidth;
            canvas.height = canvasHeight;
            context = canvas.getContext('2d');

            if (options.fillColor) {
                context.fillStyle = options.fillColor;
                context.fillRect(0, 0, canvasWidth, canvasHeight);
            }

            // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
            context.drawImage.apply(context, (function () {
                var source = getSourceCanvas(this.$clone[0], this.image);
                var sourceWidth = source.width;
                var sourceHeight = source.height;
                var canvas = this.canvas;
                var params = [source];

                // Source canvas
                var srcX = data.x + canvas.naturalWidth * (abs(data.scaleX || 1) - 1) / 2;
                var srcY = data.y + canvas.naturalHeight * (abs(data.scaleY || 1) - 1) / 2;
                var srcWidth;
                var srcHeight;

                // Destination canvas
                var dstX;
                var dstY;
                var dstWidth;
                var dstHeight;

                if (srcX <= -originalWidth || srcX > sourceWidth) {
                    srcX = srcWidth = dstX = dstWidth = 0;
                } else if (srcX <= 0) {
                    dstX = -srcX;
                    srcX = 0;
                    srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX);
                } else if (srcX <= sourceWidth) {
                    dstX = 0;
                    srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX);
                }

                if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) {
                    srcY = srcHeight = dstY = dstHeight = 0;
                } else if (srcY <= 0) {
                    dstY = -srcY;
                    srcY = 0;
                    srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY);
                } else if (srcY <= sourceHeight) {
                    dstY = 0;
                    srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
                }

                // All the numerical parameters should be integer for `drawImage` (#476)
                params.push(floor(srcX), floor(srcY), floor(srcWidth), floor(srcHeight));

                // Scale destination sizes
                if (scaledRatio) {
                    dstX *= scaledRatio;
                    dstY *= scaledRatio;
                    dstWidth *= scaledRatio;
                    dstHeight *= scaledRatio;
                }

                // Avoid "IndexSizeError" in IE and Firefox
                if (dstWidth > 0 && dstHeight > 0) {
                    params.push(floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));
                }

                return params;
            }).call(this));

            return canvas;
        },

        /**
         * Change the aspect ratio of the crop box
         *
         * @param {Number} aspectRatio
         */
        setAspectRatio: function (aspectRatio) {
            var options = this.options;

            if (!this.isDisabled && !isUndefined(aspectRatio)) {

                // 0 -> NaN
                options.aspectRatio = max(0, aspectRatio) || NaN;

                if (this.isBuilt) {
                    this.initCropBox();

                    if (this.isCropped) {
                        this.renderCropBox();
                    }
                }
            }
        },

        /**
         * Change the drag mode
         *
         * @param {String} mode (optional)
         */
        setDragMode: function (mode) {
            var options = this.options;
            var croppable;
            var movable;

            if (this.isLoaded && !this.isDisabled) {
                croppable = mode === ACTION_CROP;
                movable = options.movable && mode === ACTION_MOVE;
                mode = (croppable || movable) ? mode : ACTION_NONE;

                this.$dragBox.
                  data(DATA_ACTION, mode).
                  toggleClass(CLASS_CROP, croppable).
                  toggleClass(CLASS_MOVE, movable);

                if (!options.cropBoxMovable) {

                    // Sync drag mode to crop box when it is not movable(#300)
                    this.$face.
                      data(DATA_ACTION, mode).
                      toggleClass(CLASS_CROP, croppable).
                      toggleClass(CLASS_MOVE, movable);
                }
            }
        }
    };

    Cropper.DEFAULTS = {

        // Define the view mode of the cropper
        viewMode: 0, // 0, 1, 2, 3

        // Define the dragging mode of the cropper
        dragMode: 'crop', // 'crop', 'move' or 'none'

        // Define the aspect ratio of the crop box
        aspectRatio: NaN,

        // An object with the previous cropping result data
        data: null,

        // A jQuery selector for adding extra containers to preview
        preview: '',

        // Re-render the cropper when resize the window
        responsive: true,

        // Restore the cropped area after resize the window
        restore: true,

        // Check if the current image is a cross-origin image
        checkCrossOrigin: true,

        // Check the current image's Exif Orientation information
        checkOrientation: true,

        // Show the black modal
        modal: true,

        // Show the dashed lines for guiding
        guides: true,

        // Show the center indicator for guiding
        center: true,

        // Show the white modal to highlight the crop box
        highlight: true,

        // Show the grid background
        background: true,

        // Enable to crop the image automatically when initialize
        autoCrop: true,

        // Define the percentage of automatic cropping area when initializes
        autoCropArea: 0.8,

        // Enable to move the image
        movable: true,

        // Enable to rotate the image
        rotatable: true,

        // Enable to scale the image
        scalable: true,

        // Enable to zoom the image
        zoomable: true,

        // Enable to zoom the image by dragging touch
        zoomOnTouch: true,

        // Enable to zoom the image by wheeling mouse
        zoomOnWheel: true,

        // Define zoom ratio when zoom the image by wheeling mouse
        wheelZoomRatio: 0.1,

        // Enable to move the crop box
        cropBoxMovable: true,

        // Enable to resize the crop box
        cropBoxResizable: true,

        // Toggle drag mode between "crop" and "move" when click twice on the cropper
        toggleDragModeOnDblclick: true,

        // Size limitation
        minCanvasWidth: 0,
        minCanvasHeight: 0,
        minCropBoxWidth: 0,
        minCropBoxHeight: 0,
        minContainerWidth: 200,
        minContainerHeight: 100,

        // Shortcuts of events
        build: null,
        built: null,
        cropstart: null,
        cropmove: null,
        cropend: null,
        crop: null,
        zoom: null
    };

    Cropper.setDefaults = function (options) {
        $.extend(Cropper.DEFAULTS, options);
    };

    Cropper.TEMPLATE = (
      '<div class="cropper-container">' +
        '<div class="cropper-wrap-box">' +
          '<div class="cropper-canvas"></div>' +
        '</div>' +
        '<div class="cropper-drag-box"></div>' +
        '<div class="cropper-crop-box">' +
          '<span class="cropper-view-box"></span>' +
          '<span class="cropper-dashed dashed-h"></span>' +
          '<span class="cropper-dashed dashed-v"></span>' +
          '<span class="cropper-center"></span>' +
          '<span class="cropper-face"></span>' +
          '<span class="cropper-line line-e" data-action="e"></span>' +
          '<span class="cropper-line line-n" data-action="n"></span>' +
          '<span class="cropper-line line-w" data-action="w"></span>' +
          '<span class="cropper-line line-s" data-action="s"></span>' +
          '<span class="cropper-point point-e" data-action="e"></span>' +
          '<span class="cropper-point point-n" data-action="n"></span>' +
          '<span class="cropper-point point-w" data-action="w"></span>' +
          '<span class="cropper-point point-s" data-action="s"></span>' +
          '<span class="cropper-point point-ne" data-action="ne"></span>' +
          '<span class="cropper-point point-nw" data-action="nw"></span>' +
          '<span class="cropper-point point-sw" data-action="sw"></span>' +
          '<span class="cropper-point point-se" data-action="se"></span>' +
        '</div>' +
      '</div>'
    );

    // Save the other cropper
    Cropper.other = $.fn.cropper;

    // Register as jQuery plugin
    $.fn.cropper = function (option) {
        var args = toArray(arguments, 1);
        var result;

        this.each(function () {
            var $this = $(this);
            var data = $this.data(NAMESPACE);
            var options;
            var fn;

            if (!data) {
                if (/destroy/.test(option)) {
                    return;
                }

                options = $.extend({}, $this.data(), $.isPlainObject(option) && option);
                $this.data(NAMESPACE, (data = new Cropper(this, options)));
            }

            if (typeof option === 'string' && $.isFunction(fn = data[option])) {
                result = fn.apply(data, args);
            }
        });

        return isUndefined(result) ? this : result;
    };

    $.fn.cropper.Constructor = Cropper;
    $.fn.cropper.setDefaults = Cropper.setDefaults;

    // No conflict
    $.fn.cropper.noConflict = function () {
        $.fn.cropper = Cropper.other;
        return this;
    };

});


},{"jquery":214}],176:[function(require,module,exports){
(function (global){
/*!
 * crosstab JavaScript Library v0.2.12
 * https://github.com/tejacques/crosstab
 *
 * License: Apache 2.0 https://github.com/tejacques/crosstab/blob/master/LICENSE
 *
 *  Copyright 2015 Tom Jacques
 *
 *  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
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
/* global define */
/* global global */
; (function (window, define) {
    define('crosstab', function (require, exports, module) {
        'use strict';

        // --- Handle Support ---
        // See: http://detectmobilebrowsers.com/about
        var useragent = (window.navigator && (window.navigator.userAgent || window.navigator.vendor)) || window.opera || "none";
        var isMobile = (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(useragent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(useragent.substr(0, 4)));

        var localStorage;
        try {
            localStorage = window.localStorage;
            localStorage = window['ie8-eventlistener/storage'] || window.localStorage;
        } catch (e) {
            // New versions of Firefox throw a Security exception
            // if cookies are disabled. See
            // https://bugzilla.mozilla.org/show_bug.cgi?id=1028153
        }

        // When Safari on OS X or iOS is in private browsing mode,
        // calling localStorage.setItem throws an exception.
        //
        // "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made
        // to add something to storage that exceeded the quota."
        var setItemAllowed = true;
        try {
            localStorage.setItem('__crosstab', '');
            localStorage.removeItem('__crosstab');
        } catch (e) {
            setItemAllowed = false;
        }

        // Other reasons
        var frozenTabEnvironment = false;

        function notSupported() {
            if (crosstab.supported) return;
            var errorMsg = 'crosstab not supported';
            var reasons = [];
            if (!localStorage) {
                reasons.push('localStorage not availabe');
            }
            if (!window.addEventListener) {
                reasons.push('addEventListener not available');
            }
            if (isMobile) {
                reasons.push('mobile browser');
            }
            if (frozenTabEnvironment) {
                reasons.push('frozen tab environment detected');
            }
            if (!setItemAllowed) {
                reasons.push('localStorage.setItem not allowed');
            }

            if (reasons.length > 0) {
                errorMsg += ': ' + reasons.join(', ');
            }

            throw new Error(errorMsg);
        }

        // --- Utility ---
        var util = {
            keys: {
                MESSAGE_KEY: 'crosstab.MESSAGE_KEY',
                TABS_KEY: 'crosstab.TABS_KEY',
                MASTER_TAB: 'MASTER_TAB',
                SUPPORTED_KEY: 'crosstab.SUPPORTED',
                FROZEN_TAB_ENVIRONMENT: 'crosstab.FROZEN_TAB_ENVIRONMENT'
            }
        };

        util.isArray = Array.isArray || function (arr) {
            return arr instanceof Array;
        };

        util.isNumber = function (num) {
            return typeof num === 'number';
        };

        util.isFunction = function (fn) {
            return typeof fn === 'function';
        };

        util.forEachObj = function (obj, fn) {
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    fn.call(obj, obj[key], key, obj);
                }
            }
        };

        util.forEachArr = function (arr, fn) {
            var len = arr.length;
            for (var i = 0; i < len; i++) {
                fn.call(arr, arr[i], i, arr);
            }
        };

        util.forEach = function (thing, fn) {
            if (util.isArray(thing)) {
                util.forEachArr(thing, fn);
            } else {
                util.forEachObj(thing, fn);
            }
        };

        util.map = function (thing, fn) {
            var res = [];
            util.forEach(thing, function (item, key, obj) {
                res.push(fn(item, key, obj));
            });

            return res;
        };

        util.filter = function (thing, fn) {
            var isArr = util.isArray(thing);
            var res = isArr ? [] : {};

            if (isArr) {
                util.forEachArr(thing, function (value, key) {
                    if (fn(value, key)) {
                        res.push(value);
                    }
                });
            } else {
                util.forEachObj(thing, function (value, key) {
                    if (fn(value, key)) {
                        res[key] = value;
                    }
                });
            }

            return res;
        };

        util.reduce = function (thing, fn, accumulator) {
            var first = arguments.length < 3;

            util.forEach(thing, function (item, key, obj) {
                if (first) {
                    accumulator = item;
                    first = false;
                } else {
                    accumulator = fn(accumulator, item, key, obj);
                }
            });

            return accumulator;
        };

        util.now = function () {
            return (new Date()).getTime();
        };

        util.tabs = getStoredTabs();

        util.eventTypes = {
            becomeMaster: 'becomeMaster',
            demoteFromMaster: 'demotedFromMaster',
            tabUpdated: 'tabUpdated',
            tabClosed: 'tabClosed',
            tabPromoted: 'tabPromoted'
        };

        util.storageEventKeys = util.reduce(util.keys, function (keys, val) {
            keys[val] = 1;
            return keys;
        }, {});

        // --- Events ---
        // node.js style events, with the main difference being able
        // to add/remove events by key.
        util.createEventHandler = function () {
            var events = {};
            var subscribeKeyToListener = {};

            var findHandlerByKey = function (event, key) {
                var handler;
                if (subscribeKeyToListener[event]) {
                    handler = subscribeKeyToListener[event][key];
                }
                return handler;
            };

            var findHandlerIndex = function (event, listener) {
                var listenerIndex = -1;
                var eventList = events[event];
                if (eventList && listener) {
                    var len = eventList.length || 0;
                    for (var i = 0; i < len; i++) {
                        if (eventList[i] === listener) {
                            listenerIndex = i;
                            break;
                        }
                    }
                }
                return listenerIndex;
            };

            var addListener = function (event, listener, key) {
                var handlers = listeners(event);

                var storedHandler = findHandlerByKey(event, key);
                var listenerIndex;

                if (storedHandler === undefined) {
                    listenerIndex = handlers.length;
                    handlers[listenerIndex] = listener;

                    if (!subscribeKeyToListener[event]) {
                        (subscribeKeyToListener[event] = {});
                    }

                    if (key) {
                        subscribeKeyToListener[event][key] = listener;
                    }
                } else {
                    listenerIndex = findHandlerIndex(event, storedHandler);
                    handlers[listenerIndex] = listener;
                }

                return key || listener;
            };

            var removeListener = function (event, key) {
                var handler = util.isFunction(key)
                    ? key
                    : findHandlerByKey(event, key);

                var listenerIndex = findHandlerIndex(event, handler);
                if (listenerIndex === -1) return false;

                if (events[event] && events[event][listenerIndex]) {
                    events[event].splice(listenerIndex, 1);
                    delete subscribeKeyToListener[event][key];
                    return true;
                }
                return false;
            };

            var removeAllListeners = function (event) {
                var successful = false;
                if (event) {
                    if (events[event]) {
                        delete events[event];
                        successful = true;
                    }
                    if (subscribeKeyToListener[event]) {
                        delete subscribeKeyToListener[event];
                        successful = successful && true;
                    }
                } else {
                    events = {};
                    subscribeKeyToListener = {};
                    successful = true;
                }
                return successful;
            };

            var emit = function (event) {
                var args = Array.prototype.slice.call(arguments, 1);
                var handlers = listeners(event);

                util.forEach(handlers, function (listener) {
                    if (util.isFunction(listener)) {
                        listener.apply(this, args);
                    }
                });
            };

            var once = function (event, listener, key) {
                // Generate a unique id for this listener
                while (!key || (findHandlerByKey(event, key) !== undefined)) {
                    key = util.generateId();
                }

                addListener(event, function () {
                    removeListener(event, key);
                    var args = Array.prototype.slice.call(arguments);
                    listener.apply(this, args);
                }, key);

                return key;
            };

            var listeners = function (event) {
                var handlers = events[event] = events[event] || [];
                return handlers;
            };

            var destructor = function () {
                clearInterval(crosstab.keepAliveInterval)
                removeAllListeners();
            };

            return {
                addListener: addListener,
                destructor: destructor,
                on: addListener,
                off: function (event, key) {
                    var argsLen = arguments.length;
                    if (!argsLen) {
                        return removeAllListeners();
                    } else if (argsLen === 1) {
                        return removeAllListeners(event);
                    } else {
                        return removeListener(event, key);
                    }
                },
                once: once,
                emit: emit,
                listeners: listeners,
                removeListener: removeListener,
                removeAllListeners: removeAllListeners
            };
        };

        // --- Setup Events ---
        var eventHandler = util.createEventHandler();

        // wrap eventHandler so that setting it will not blow up
        // any of the internal workings
        util.events = {
            addListener: eventHandler.addListener,
            on: eventHandler.on,
            off: eventHandler.off,
            once: eventHandler.once,
            emit: eventHandler.emit,
            listeners: eventHandler.listeners,
            removeListener: eventHandler.removeListener,
            removeAllListeners: eventHandler.removeAllListeners,
            destructor: eventHandler.destructor
        };

        var lastNewValue;
        var lastOldValue;
        function onStorageEvent(event) {
            // Only handle crosstab events
            if (!event || !(event.key in util.storageEventKeys)) {
                return;
            }

            var eventValue;
            try {
                eventValue = event.newValue ? JSON.parse(event.newValue) : {};
            } catch (e) {
                eventValue = {};
            }
            if (!eventValue || !eventValue.id || eventValue.id === crosstab.id) {
                // This is to force IE to behave properly
                return;
            }
            if (event.newValue === lastNewValue && event.oldValue === lastOldValue) {
                // Fix bug in IE11 where StorageEvents in iframes are sent twice.
                return;
            }
            lastNewValue = event.newValue;
            lastOldValue = event.oldValue;
            if (event.key === util.keys.MESSAGE_KEY) {
                var message = eventValue.data;
                // only handle if this message was meant for this tab.
                if (!message.destination || message.destination === crosstab.id) {
                    eventHandler.emit(message.event, message);
                }
            } else if (event.key === util.keys.FROZEN_TAB_ENVIRONMENT) {
                frozenTabEnvironment = eventValue.data;
                crosstab.supported = crosstab.supported && !eventValue.data;
            } else if (event.key === util.keys.SUPPORTED_KEY) {
                crosstab.supported = crosstab.supported && eventValue.data;
            }
        }

        function setLocalStorageItem(key, data) {
            var storageItem = {
                id: crosstab.id,
                data: data,
                timestamp: util.now()
            };

            // TODO: Добавить обработку исключения на тот случай, если LocalStorage переполнен
            try {
                localStorage.setItem(key, JSON.stringify(storageItem));
            } catch (ex) {
                console.error(ex);
            }
        }

        function getLocalStorageItem(key) {
            var item = getLocalStorageRaw(key);
            return item.data;
        }

        function getLocalStorageRaw(key) {
            var json = localStorage ? localStorage.getItem(key) : null;
            var item = json ? JSON.parse(json) : {};
            return item;
        }

        function unload() {
            crosstab.stopKeepalive = true;
            var numTabs = 0;
            util.forEach(util.tabs, function (tab, key) {
                if (key !== util.keys.MASTER_TAB) {
                    numTabs++;
                }
            });

            if (numTabs === 1) {
                util.tabs = {};
                setStoredTabs();
            } else {
                broadcast(util.eventTypes.tabClosed, crosstab.id);
            }

        }

        function restoreLoop() {
            crosstab.stopKeepalive = false;
            keepaliveLoop();
        }

        function swapUnloadEvents() {
            // `beforeunload` replaced by `unload` (IE11 will be smart now)
            window.removeEventListener('beforeunload', unload, false);
            window.addEventListener('unload', unload, false);
            restoreLoop();
        }

        function getMaster() {
            return util.tabs[util.keys.MASTER_TAB];
        }

        function setMaster(newMaster) {
            util.tabs[util.keys.MASTER_TAB] = newMaster;
        }

        function deleteMaster() {
            delete util.tabs[util.keys.MASTER_TAB];
        }

        function getMasterId() {
            var master = getMaster();

            return master ? master.id : 0;
        }

        function isMaster() {
            return getMasterId() === crosstab.id;
        }

        function masterTabElection() {
            var maxId = null;
            util.forEach(util.tabs, function (tab) {
                if (!maxId || tab.id < maxId) {
                    maxId = tab.id;
                }
            });

            // only broadcast the promotion if I am the new master
            if (maxId === crosstab.id) {
                broadcast(util.eventTypes.tabPromoted, crosstab.id);
            } else {
                // this is done so that in the case where multiple tabs are being
                // started at the same time, and there is no current saved tab
                // information, we will still have a value set for the master tab
                setMaster({
                    id: maxId,
                    lastUpdated: util.now()
                });
            }
        }

        // Handle other tabs closing by updating internal tab model, and promoting
        // self if we are the lowest tab id
        eventHandler.addListener(util.eventTypes.tabClosed, function (message) {
            var id = message.data;
            if (id in util.tabs) {
                delete util.tabs[id];
            }

            var master = getMaster();
            if (!master || master.id === id) {
                // If the master was the closed tab, delete it and the highest
                // tab ID becomes the new master, which will save the tabs
                if (master) {
                    deleteMaster();
                }
                masterTabElection();
            } else if (master.id === crosstab.id) {
                // If I am master, save the new tabs out
                setStoredTabs();
            }
        });

        eventHandler.addListener(util.eventTypes.tabUpdated, function (message) {
            var tab = message.data;
            util.tabs[tab.id] = tab;

            // If there is no master, hold an election
            if (!getMaster()) {
                masterTabElection();
            }

            if (getMasterId() === tab.id) {
                setMaster(tab);
            }
            if (isMaster()) {
                // If I am master, save the new tabs out
                setStoredTabs();
            }
        });

        var bullying;
        eventHandler.addListener(util.eventTypes.tabPromoted, function (message) {
            var id = message.data;
            var lastUpdated = message.timestamp;
            var previousMaster = getMasterId();

            // Bully out competing broadcasts if our id is lower
            if (crosstab.id < id) {
                if (!bullying) {
                    bullying = setTimeout(function () {
                        bullying = 0;
                        broadcast(util.eventTypes.tabPromoted, crosstab.id);
                    }, 0);
                }
                return;
            }

            setMaster({
                id: id,
                lastUpdated: lastUpdated
            });

            if (isMaster()) {
                // set the tabs in localStorage
                setStoredTabs();
            }
            if (isMaster()
                && previousMaster !== crosstab.id) {
                // emit the become master event so we can handle it accordingly
                util.events.emit(util.eventTypes.becomeMaster);
            } else if (!isMaster()
                && previousMaster === crosstab.id) {
                // emit the demoted from master event so we can clean up resources
                util.events.emit(util.eventTypes.demoteFromMaster);
            }
        });

        function pad(num, width, padChar) {
            padChar = padChar || '0';
            var numStr = (num.toString());

            if (numStr.length >= width) {
                return numStr;
            }

            return new Array(width - numStr.length + 1).join(padChar) + numStr;
        }

        util.generateId = function () {
            /*jshint bitwise: false*/
            return util.now().toString() + pad((Math.random() * 0x7FFFFFFF) | 0, 10);
        };

        // --- Setup message sending and handling ---
        function broadcast(event, data, destination) {
            if (!crosstab.supported) {
                notSupported();
            }

            var message = {
                id: util.generateId(),
                event: event,
                data: data,
                destination: destination,
                origin: crosstab.id,
                timestamp: util.now()
            };

            // If the destination differs from the origin send it out, otherwise
            // handle it locally
            if (message.destination !== message.origin) {
                setLocalStorageItem(util.keys.MESSAGE_KEY, message);
            }

            if (!message.destination || message.destination === message.origin) {
                eventHandler.emit(event, message);
            }
        }

        function broadcastMaster(event, data) {
            broadcast(event, data, getMaster().id);
        }

        // ---- Return ----
        var setupComplete = false;
        util.events.once('setupComplete', function () {
            setupComplete = true;
        });

        var crosstab = function (fn) {
            if (setupComplete) {
                fn();
            } else {
                util.events.once('setupComplete', fn);
            }
        };

        crosstab.id = util.generateId();
        crosstab.supported = !!localStorage && window.addEventListener && !isMobile && setItemAllowed;
        crosstab.util = util;
        crosstab.broadcast = broadcast;
        crosstab.broadcastMaster = broadcastMaster;
        crosstab.on = util.events.on;
        crosstab.once = util.events.once;
        crosstab.off = util.events.off;

        // 10 minute timeout
        var CACHE_TIMEOUT = 10 * 60 * 1000;

        // --- Crosstab supported ---
        // Check to see if the global frozen tab environment key or supported key has been set.
        if (!setupComplete && crosstab.supported) {
            var frozenTabsRaw = getLocalStorageRaw(util.keys.FROZEN_TAB_ENVIRONMENT);

            if (frozenTabsRaw.timestamp) {
                var frozenTabs = frozenTabsRaw.data;
                if (util.now() - frozenTabsRaw.timestamp > CACHE_TIMEOUT) {
                    localStorage.removeItem(util.keys.FROZEN_TAB_ENVIRONMENT);
                } else if (frozenTabs === true) {
                    frozenTabEnvironmentDetected();
                }
            }

            var supportedRaw = getLocalStorageRaw(util.keys.SUPPORTED_KEY);

            if (supportedRaw.timestamp) {
                var supported = supportedRaw.data;

                if (util.now() - supportedRaw.timestamp > CACHE_TIMEOUT) {
                    localStorage.removeItem(util.keys.SUPPORTED_KEY);
                } else if (supported === false || supported === true) {
                    // As long as it is explicitely set, use the value
                    crosstab.supported = supported;
                    util.events.emit('setupComplete');
                }
            }
        }

        function frozenTabEnvironmentDetected() {
            crosstab.supported = false;
            frozenTabEnvironment = true;
            setLocalStorageItem(util.keys.FROZEN_TAB_ENVIRONMENT, true);
            setLocalStorageItem(util.keys.SUPPORTED_KEY, false);
        }

        // --- Tab Setup ---
        // 3 second keepalive
        var TAB_KEEPALIVE = 3 * 1000;
        // 5 second timeout
        var TAB_TIMEOUT = 5 * 1000;
        // 500 ms ping timeout
        var PING_TIMEOUT = 500;

        function getStoredTabs() {
            var storedTabs = getLocalStorageItem(util.keys.TABS_KEY);
            util.tabs = storedTabs || util.tabs || {};
            return util.tabs;
        }

        function setStoredTabs() {
            setLocalStorageItem(util.keys.TABS_KEY, util.tabs);
        }

        function keepalive() {
            var now = util.now();

            var myTab = {
                id: crosstab.id,
                lastUpdated: now,
                url: window.location.href
            };

            // broadcast tabUpdated event
            broadcast(util.eventTypes.tabUpdated, myTab);

            // broadcast tabClosed event for each tab that timed out
            function stillAlive(tab) {
                return now - tab.lastUpdated < TAB_TIMEOUT;
            }

            function notAlive(tab, key) {
                return key !== util.keys.MASTER_TAB && !stillAlive(tab);
            }

            var deadTabs = util.filter(util.tabs, notAlive);
            util.forEach(deadTabs, function (tab) {
                broadcast(util.eventTypes.tabClosed, tab.id);
            });

            // check to see if setup is complete
            if (!setupComplete) {
                var master = getMaster();
                // ping master
                if (master && master.id !== myTab.id) {
                    var timeout;
                    var start;

                    crosstab.util.events.once('PONG', function () {
                        if (!setupComplete) {
                            clearTimeout(timeout);
                            // set supported to true / frozen to false
                            setLocalStorageItem(
                                util.keys.SUPPORTED_KEY,
                                true);
                            setLocalStorageItem(
                                util.keys.FROZEN_TAB_ENVIRONMENT,
                                false);
                            util.events.emit('setupComplete');
                        }
                    });

                    start = util.now();

                    // There is a nested timeout here. We'll give it 100ms
                    // timeout, with iters "yields" to the event loop. So at least
                    // iters number of blocks of javascript will be able to run
                    // covering at least 100ms
                    var recursiveTimeout = function (iters) {
                        var diff = util.now() - start;

                        if (!setupComplete) {
                            if (iters <= 0 && diff > PING_TIMEOUT) {
                                frozenTabEnvironmentDetected();
                                util.events.emit('setupComplete');
                            } else {
                                timeout = setTimeout(function () {
                                    recursiveTimeout(iters - 1);
                                }, 5);
                            }
                        }
                    };

                    var iterations = 5;
                    timeout = setTimeout(function () {
                        recursiveTimeout(5);
                    }, PING_TIMEOUT - 5 * iterations);
                    crosstab.broadcastMaster('PING');
                } else if (master && master.id === myTab.id) {
                    util.events.emit('setupComplete');
                }
            }
        }

        function keepaliveLoop() {
            if (crosstab.supported && !crosstab.stopKeepalive) {
                keepalive();
            }
        }

        // --- Check if crosstab is supported ---
        if (!crosstab.supported) {
            crosstab.broadcast = notSupported;
        } else {
            // ---- Setup Storage Listener
            window.addEventListener('storage', onStorageEvent, false);
            // start with the `beforeunload` event due to IE11
            window.addEventListener('beforeunload', unload, false);
            // swap `beforeunload` to `unload` after DOM is loaded
            window.addEventListener('DOMContentLoaded', swapUnloadEvents, false);

            util.events.on('PING', function (message) {
                // only handle direct messages
                if (!message.destination || message.destination !== crosstab.id) {
                    return;
                }

                if (util.now() - message.timestamp < PING_TIMEOUT) {
                    crosstab.broadcast('PONG', null, message.origin);
                }
            });

            crosstab.keepAliveInterval = setInterval(keepaliveLoop, TAB_KEEPALIVE);
            keepaliveLoop();
        }

        module.exports = crosstab;

        /*!
         * UMD/AMD/Global context Module Loader wrapper
         *
         * This wrapper will try to use a module loader with the
         * following priority:
         *
         *  1.) AMD
         *  2.) CommonJS
         *  3.) Context Variable (this)
         *    - window in the browser
         *    - module.exports in node and browserify
         */
    });
})(
    // First arg -- the global object in the browser or node
    typeof window == 'object' ? window : global,
    // Second arg -- the define object
    typeof define == 'function' && define.amd
    ? define
    : (function (context) {
        'use strict';
        return typeof module == 'object' ? function (name, factory) {
            factory(require, exports, module);
        }
        : function (name, factory) {
            var module = {
                exports: {}
            };
            var require = function (n) {
                if (n === 'jquery') {
                    n = 'jQuery';
                }
                return context[n];
            };

            factory(require, module.exports, module);
            context[name] = module.exports;
        };
    })(this));
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})

},{}],177:[function(require,module,exports){
/**
 * FingerprintJS v4.6.0 - Copyright (c) FingerprintJS, Inc, 2025 (https://fingerprint.com)
 *
 * Licensed under Business Source License 1.1 https://mariadb.com/bsl11/
 * Licensor: FingerprintJS, Inc.
 * Licensed Work: FingerprintJS browser fingerprinting library
 * Additional Use Grant: None
 * Change Date: Four years from first release for the specific version.
 * Change License: MIT, text at https://opensource.org/license/mit/ with the following copyright notice:
 * Copyright 2015-present FingerprintJS, Inc.
 */

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.FingerprintJS = {}));
})(this, (function (exports) { 'use strict';

    /******************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */
    /* global Reflect, Promise */


    var __assign = function() {
        __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
        return __assign.apply(this, arguments);
    };

    function __awaiter(thisArg, _arguments, P, generator) {
        function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
        return new (P || (P = Promise))(function (resolve, reject) {
            function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
            function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
            function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
            step((generator = generator.apply(thisArg, _arguments || [])).next());
        });
    }

    function __generator(thisArg, body) {
        var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
        return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
        function verb(n) { return function (v) { return step([n, v]); }; }
        function step(op) {
            if (f) throw new TypeError("Generator is already executing.");
            while (g && (g = 0, op[0] && (_ = 0)), _) try {
                if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
                if (y = 0, t) op = [op[0] & 2, t.value];
                switch (op[0]) {
                    case 0: case 1: t = op; break;
                    case 4: _.label++; return { value: op[1], done: false };
                    case 5: _.label++; y = op[1]; op = [0]; continue;
                    case 7: op = _.ops.pop(); _.trys.pop(); continue;
                    default:
                        if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                        if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                        if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                        if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                        if (t[2]) _.ops.pop();
                        _.trys.pop(); continue;
                }
                op = body.call(thisArg, _);
            } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
            if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
        }
    }

    function __spreadArray(to, from, pack) {
        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
            if (ar || !(i in from)) {
                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
                ar[i] = from[i];
            }
        }
        return to.concat(ar || Array.prototype.slice.call(from));
    }

    var version = "4.6.0";

    function wait(durationMs, resolveWith) {
        return new Promise(function (resolve) { return setTimeout(resolve, durationMs, resolveWith); });
    }
    /**
     * Allows asynchronous actions and microtasks to happen.
     */
    function releaseEventLoop() {
        // Don't use setTimeout because Chrome throttles it in some cases causing very long agent execution:
        // https://stackoverflow.com/a/6032591/1118709
        // https://github.com/chromium/chromium/commit/0295dd09496330f3a9103ef7e543fa9b6050409b
        // Reusing a MessageChannel object gives no noticeable benefits
        return new Promise(function (resolve) {
            var channel = new MessageChannel();
            channel.port1.onmessage = function () { return resolve(); };
            channel.port2.postMessage(null);
        });
    }
    function requestIdleCallbackIfAvailable(fallbackTimeout, deadlineTimeout) {
        if (deadlineTimeout === void 0) { deadlineTimeout = Infinity; }
        var requestIdleCallback = window.requestIdleCallback;
        if (requestIdleCallback) {
            // The function `requestIdleCallback` loses the binding to `window` here.
            // `globalThis` isn't always equal `window` (see https://github.com/fingerprintjs/fingerprintjs/issues/683).
            // Therefore, an error can occur. `call(window,` prevents the error.
            return new Promise(function (resolve) { return requestIdleCallback.call(window, function () { return resolve(); }, { timeout: deadlineTimeout }); });
        }
        else {
            return wait(Math.min(fallbackTimeout, deadlineTimeout));
        }
    }
    function isPromise(value) {
        return !!value && typeof value.then === 'function';
    }
    /**
     * Calls a maybe asynchronous function without creating microtasks when the function is synchronous.
     * Catches errors in both cases.
     *
     * If just you run a code like this:
     * ```
     * console.time('Action duration')
     * await action()
     * console.timeEnd('Action duration')
     * ```
     * The synchronous function time can be measured incorrectly because another microtask may run before the `await`
     * returns the control back to the code.
     */
    function awaitIfAsync(action, callback) {
        try {
            var returnedValue = action();
            if (isPromise(returnedValue)) {
                returnedValue.then(function (result) { return callback(true, result); }, function (error) { return callback(false, error); });
            }
            else {
                callback(true, returnedValue);
            }
        }
        catch (error) {
            callback(false, error);
        }
    }
    /**
     * If you run many synchronous tasks without using this function, the JS main loop will be busy and asynchronous tasks
     * (e.g. completing a network request, rendering the page) won't be able to happen.
     * This function allows running many synchronous tasks such way that asynchronous tasks can run too in background.
     */
    function mapWithBreaks(items, callback, loopReleaseInterval) {
        if (loopReleaseInterval === void 0) { loopReleaseInterval = 16; }
        return __awaiter(this, void 0, void 0, function () {
            var results, lastLoopReleaseTime, i, now;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        results = Array(items.length);
                        lastLoopReleaseTime = Date.now();
                        i = 0;
                        _a.label = 1;
                    case 1:
                        if (!(i < items.length)) return [3 /*break*/, 4];
                        results[i] = callback(items[i], i);
                        now = Date.now();
                        if (!(now >= lastLoopReleaseTime + loopReleaseInterval)) return [3 /*break*/, 3];
                        lastLoopReleaseTime = now;
                        return [4 /*yield*/, releaseEventLoop()];
                    case 2:
                        _a.sent();
                        _a.label = 3;
                    case 3:
                        ++i;
                        return [3 /*break*/, 1];
                    case 4: return [2 /*return*/, results];
                }
            });
        });
    }
    /**
     * Makes the given promise never emit an unhandled promise rejection console warning.
     * The promise will still pass errors to the next promises.
     * Returns the input promise for convenience.
     *
     * Otherwise, promise emits a console warning unless it has a `catch` listener.
     */
    function suppressUnhandledRejectionWarning(promise) {
        promise.then(undefined, function () { return undefined; });
        return promise;
    }

    /*
     * This file contains functions to work with pure data only (no browser features, DOM, side effects, etc).
     */
    /**
     * Does the same as Array.prototype.includes but has better typing
     */
    function includes(haystack, needle) {
        for (var i = 0, l = haystack.length; i < l; ++i) {
            if (haystack[i] === needle) {
                return true;
            }
        }
        return false;
    }
    /**
     * Like `!includes()` but with proper typing
     */
    function excludes(haystack, needle) {
        return !includes(haystack, needle);
    }
    /**
     * Be careful, NaN can return
     */
    function toInt(value) {
        return parseInt(value);
    }
    /**
     * Be careful, NaN can return
     */
    function toFloat(value) {
        return parseFloat(value);
    }
    function replaceNaN(value, replacement) {
        return typeof value === 'number' && isNaN(value) ? replacement : value;
    }
    function countTruthy(values) {
        return values.reduce(function (sum, value) { return sum + (value ? 1 : 0); }, 0);
    }
    function round(value, base) {
        if (base === void 0) { base = 1; }
        if (Math.abs(base) >= 1) {
            return Math.round(value / base) * base;
        }
        else {
            // Sometimes when a number is multiplied by a small number, precision is lost,
            // for example 1234 * 0.0001 === 0.12340000000000001, and it's more precise divide: 1234 / (1 / 0.0001) === 0.1234.
            var counterBase = 1 / base;
            return Math.round(value * counterBase) / counterBase;
        }
    }
    /**
     * Parses a CSS selector into tag name with HTML attributes.
     * Only single element selector are supported (without operators like space, +, >, etc).
     *
     * Multiple values can be returned for each attribute. You decide how to handle them.
     */
    function parseSimpleCssSelector(selector) {
        var _a, _b;
        var errorMessage = "Unexpected syntax '".concat(selector, "'");
        var tagMatch = /^\s*([a-z-]*)(.*)$/i.exec(selector);
        var tag = tagMatch[1] || undefined;
        var attributes = {};
        var partsRegex = /([.:#][\w-]+|\[.+?\])/gi;
        var addAttribute = function (name, value) {
            attributes[name] = attributes[name] || [];
            attributes[name].push(value);
        };
        for (;;) {
            var match = partsRegex.exec(tagMatch[2]);
            if (!match) {
                break;
            }
            var part = match[0];
            switch (part[0]) {
                case '.':
                    addAttribute('class', part.slice(1));
                    break;
                case '#':
                    addAttribute('id', part.slice(1));
                    break;
                case '[': {
                    var attributeMatch = /^\[([\w-]+)([~|^$*]?=("(.*?)"|([\w-]+)))?(\s+[is])?\]$/.exec(part);
                    if (attributeMatch) {
                        addAttribute(attributeMatch[1], (_b = (_a = attributeMatch[4]) !== null && _a !== void 0 ? _a : attributeMatch[5]) !== null && _b !== void 0 ? _b : '');
                    }
                    else {
                        throw new Error(errorMessage);
                    }
                    break;
                }
                default:
                    throw new Error(errorMessage);
            }
        }
        return [tag, attributes];
    }
    /**
     * Converts a string to UTF8 bytes
     */
    function getUTF8Bytes(input) {
        // Benchmark: https://jsbench.me/b6klaaxgwq/1
        // If you want to just count bytes, see solutions at https://jsbench.me/ehklab415e/1
        var result = new Uint8Array(input.length);
        for (var i = 0; i < input.length; i++) {
            // `charCode` is faster than encoding, so we prefer that when it's possible
            var charCode = input.charCodeAt(i);
            // In case of non-ASCII symbols we use proper encoding
            if (charCode > 127) {
                return new TextEncoder().encode(input);
            }
            result[i] = charCode;
        }
        return result;
    }

    /*
     * Based on https://github.com/karanlyons/murmurHash3.js/blob/a33d0723127e2e5415056c455f8aed2451ace208/murmurHash3.js
     */
    /**
     * Adds two 64-bit values (provided as tuples of 32-bit values)
     * and updates (mutates) first value to write the result
     */
    function x64Add(m, n) {
        var m0 = m[0] >>> 16, m1 = m[0] & 0xffff, m2 = m[1] >>> 16, m3 = m[1] & 0xffff;
        var n0 = n[0] >>> 16, n1 = n[0] & 0xffff, n2 = n[1] >>> 16, n3 = n[1] & 0xffff;
        var o0 = 0, o1 = 0, o2 = 0, o3 = 0;
        o3 += m3 + n3;
        o2 += o3 >>> 16;
        o3 &= 0xffff;
        o2 += m2 + n2;
        o1 += o2 >>> 16;
        o2 &= 0xffff;
        o1 += m1 + n1;
        o0 += o1 >>> 16;
        o1 &= 0xffff;
        o0 += m0 + n0;
        o0 &= 0xffff;
        m[0] = (o0 << 16) | o1;
        m[1] = (o2 << 16) | o3;
    }
    /**
     * Multiplies two 64-bit values (provided as tuples of 32-bit values)
     * and updates (mutates) first value to write the result
     */
    function x64Multiply(m, n) {
        var m0 = m[0] >>> 16, m1 = m[0] & 0xffff, m2 = m[1] >>> 16, m3 = m[1] & 0xffff;
        var n0 = n[0] >>> 16, n1 = n[0] & 0xffff, n2 = n[1] >>> 16, n3 = n[1] & 0xffff;
        var o0 = 0, o1 = 0, o2 = 0, o3 = 0;
        o3 += m3 * n3;
        o2 += o3 >>> 16;
        o3 &= 0xffff;
        o2 += m2 * n3;
        o1 += o2 >>> 16;
        o2 &= 0xffff;
        o2 += m3 * n2;
        o1 += o2 >>> 16;
        o2 &= 0xffff;
        o1 += m1 * n3;
        o0 += o1 >>> 16;
        o1 &= 0xffff;
        o1 += m2 * n2;
        o0 += o1 >>> 16;
        o1 &= 0xffff;
        o1 += m3 * n1;
        o0 += o1 >>> 16;
        o1 &= 0xffff;
        o0 += m0 * n3 + m1 * n2 + m2 * n1 + m3 * n0;
        o0 &= 0xffff;
        m[0] = (o0 << 16) | o1;
        m[1] = (o2 << 16) | o3;
    }
    /**
     * Provides left rotation of the given int64 value (provided as tuple of two int32)
     * by given number of bits. Result is written back to the value
     */
    function x64Rotl(m, bits) {
        var m0 = m[0];
        bits %= 64;
        if (bits === 32) {
            m[0] = m[1];
            m[1] = m0;
        }
        else if (bits < 32) {
            m[0] = (m0 << bits) | (m[1] >>> (32 - bits));
            m[1] = (m[1] << bits) | (m0 >>> (32 - bits));
        }
        else {
            bits -= 32;
            m[0] = (m[1] << bits) | (m0 >>> (32 - bits));
            m[1] = (m0 << bits) | (m[1] >>> (32 - bits));
        }
    }
    /**
     * Provides a left shift of the given int32 value (provided as tuple of [0, int32])
     * by given number of bits. Result is written back to the value
     */
    function x64LeftShift(m, bits) {
        bits %= 64;
        if (bits === 0) {
            return;
        }
        else if (bits < 32) {
            m[0] = m[1] >>> (32 - bits);
            m[1] = m[1] << bits;
        }
        else {
            m[0] = m[1] << (bits - 32);
            m[1] = 0;
        }
    }
    /**
     * Provides a XOR of the given int64 values(provided as tuple of two int32).
     * Result is written back to the first value
     */
    function x64Xor(m, n) {
        m[0] ^= n[0];
        m[1] ^= n[1];
    }
    var F1 = [0xff51afd7, 0xed558ccd];
    var F2 = [0xc4ceb9fe, 0x1a85ec53];
    /**
     * Calculates murmurHash3's final x64 mix of that block and writes result back to the input value.
     * (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the
     * only place where we need to right shift 64bit ints.)
     */
    function x64Fmix(h) {
        var shifted = [0, h[0] >>> 1];
        x64Xor(h, shifted);
        x64Multiply(h, F1);
        shifted[1] = h[0] >>> 1;
        x64Xor(h, shifted);
        x64Multiply(h, F2);
        shifted[1] = h[0] >>> 1;
        x64Xor(h, shifted);
    }
    var C1 = [0x87c37b91, 0x114253d5];
    var C2 = [0x4cf5ad43, 0x2745937f];
    var M$1 = [0, 5];
    var N1 = [0, 0x52dce729];
    var N2 = [0, 0x38495ab5];
    /**
     * Given a string and an optional seed as an int, returns a 128 bit
     * hash using the x64 flavor of MurmurHash3, as an unsigned hex.
     * All internal functions mutates passed value to achieve minimal memory allocations and GC load
     *
     * Benchmark https://jsbench.me/p4lkpaoabi/1
     */
    function x64hash128(input, seed) {
        var key = getUTF8Bytes(input);
        seed = seed || 0;
        var length = [0, key.length];
        var remainder = length[1] % 16;
        var bytes = length[1] - remainder;
        var h1 = [0, seed];
        var h2 = [0, seed];
        var k1 = [0, 0];
        var k2 = [0, 0];
        var i;
        for (i = 0; i < bytes; i = i + 16) {
            k1[0] = key[i + 4] | (key[i + 5] << 8) | (key[i + 6] << 16) | (key[i + 7] << 24);
            k1[1] = key[i] | (key[i + 1] << 8) | (key[i + 2] << 16) | (key[i + 3] << 24);
            k2[0] = key[i + 12] | (key[i + 13] << 8) | (key[i + 14] << 16) | (key[i + 15] << 24);
            k2[1] = key[i + 8] | (key[i + 9] << 8) | (key[i + 10] << 16) | (key[i + 11] << 24);
            x64Multiply(k1, C1);
            x64Rotl(k1, 31);
            x64Multiply(k1, C2);
            x64Xor(h1, k1);
            x64Rotl(h1, 27);
            x64Add(h1, h2);
            x64Multiply(h1, M$1);
            x64Add(h1, N1);
            x64Multiply(k2, C2);
            x64Rotl(k2, 33);
            x64Multiply(k2, C1);
            x64Xor(h2, k2);
            x64Rotl(h2, 31);
            x64Add(h2, h1);
            x64Multiply(h2, M$1);
            x64Add(h2, N2);
        }
        k1[0] = 0;
        k1[1] = 0;
        k2[0] = 0;
        k2[1] = 0;
        var val = [0, 0];
        switch (remainder) {
            case 15:
                val[1] = key[i + 14];
                x64LeftShift(val, 48);
                x64Xor(k2, val);
            // fallthrough
            case 14:
                val[1] = key[i + 13];
                x64LeftShift(val, 40);
                x64Xor(k2, val);
            // fallthrough
            case 13:
                val[1] = key[i + 12];
                x64LeftShift(val, 32);
                x64Xor(k2, val);
            // fallthrough
            case 12:
                val[1] = key[i + 11];
                x64LeftShift(val, 24);
                x64Xor(k2, val);
            // fallthrough
            case 11:
                val[1] = key[i + 10];
                x64LeftShift(val, 16);
                x64Xor(k2, val);
            // fallthrough
            case 10:
                val[1] = key[i + 9];
                x64LeftShift(val, 8);
                x64Xor(k2, val);
            // fallthrough
            case 9:
                val[1] = key[i + 8];
                x64Xor(k2, val);
                x64Multiply(k2, C2);
                x64Rotl(k2, 33);
                x64Multiply(k2, C1);
                x64Xor(h2, k2);
            // fallthrough
            case 8:
                val[1] = key[i + 7];
                x64LeftShift(val, 56);
                x64Xor(k1, val);
            // fallthrough
            case 7:
                val[1] = key[i + 6];
                x64LeftShift(val, 48);
                x64Xor(k1, val);
            // fallthrough
            case 6:
                val[1] = key[i + 5];
                x64LeftShift(val, 40);
                x64Xor(k1, val);
            // fallthrough
            case 5:
                val[1] = key[i + 4];
                x64LeftShift(val, 32);
                x64Xor(k1, val);
            // fallthrough
            case 4:
                val[1] = key[i + 3];
                x64LeftShift(val, 24);
                x64Xor(k1, val);
            // fallthrough
            case 3:
                val[1] = key[i + 2];
                x64LeftShift(val, 16);
                x64Xor(k1, val);
            // fallthrough
            case 2:
                val[1] = key[i + 1];
                x64LeftShift(val, 8);
                x64Xor(k1, val);
            // fallthrough
            case 1:
                val[1] = key[i];
                x64Xor(k1, val);
                x64Multiply(k1, C1);
                x64Rotl(k1, 31);
                x64Multiply(k1, C2);
                x64Xor(h1, k1);
            // fallthrough
        }
        x64Xor(h1, length);
        x64Xor(h2, length);
        x64Add(h1, h2);
        x64Add(h2, h1);
        x64Fmix(h1);
        x64Fmix(h2);
        x64Add(h1, h2);
        x64Add(h2, h1);
        return (('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) +
            ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) +
            ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) +
            ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8));
    }

    /**
     * Converts an error object to a plain object that can be used with `JSON.stringify`.
     * If you just run `JSON.stringify(error)`, you'll get `'{}'`.
     */
    function errorToObject(error) {
        var _a;
        return __assign({ name: error.name, message: error.message, stack: (_a = error.stack) === null || _a === void 0 ? void 0 : _a.split('\n') }, error);
    }
    function isFunctionNative(func) {
        return /^function\s.*?\{\s*\[native code]\s*}$/.test(String(func));
    }

    function isFinalResultLoaded(loadResult) {
        return typeof loadResult !== 'function';
    }
    /**
     * Loads the given entropy source. Returns a function that gets an entropy component from the source.
     *
     * The result is returned synchronously to prevent `loadSources` from
     * waiting for one source to load before getting the components from the other sources.
     */
    function loadSource(source, sourceOptions) {
        var sourceLoadPromise = suppressUnhandledRejectionWarning(new Promise(function (resolveLoad) {
            var loadStartTime = Date.now();
            // `awaitIfAsync` is used instead of just `await` in order to measure the duration of synchronous sources
            // correctly (other microtasks won't affect the duration).
            awaitIfAsync(source.bind(null, sourceOptions), function () {
                var loadArgs = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    loadArgs[_i] = arguments[_i];
                }
                var loadDuration = Date.now() - loadStartTime;
                // Source loading failed
                if (!loadArgs[0]) {
                    return resolveLoad(function () { return ({ error: loadArgs[1], duration: loadDuration }); });
                }
                var loadResult = loadArgs[1];
                // Source loaded with the final result
                if (isFinalResultLoaded(loadResult)) {
                    return resolveLoad(function () { return ({ value: loadResult, duration: loadDuration }); });
                }
                // Source loaded with "get" stage
                resolveLoad(function () {
                    return new Promise(function (resolveGet) {
                        var getStartTime = Date.now();
                        awaitIfAsync(loadResult, function () {
                            var getArgs = [];
                            for (var _i = 0; _i < arguments.length; _i++) {
                                getArgs[_i] = arguments[_i];
                            }
                            var duration = loadDuration + Date.now() - getStartTime;
                            // Source getting failed
                            if (!getArgs[0]) {
                                return resolveGet({ error: getArgs[1], duration: duration });
                            }
                            // Source getting succeeded
                            resolveGet({ value: getArgs[1], duration: duration });
                        });
                    });
                });
            });
        }));
        return function getComponent() {
            return sourceLoadPromise.then(function (finalizeSource) { return finalizeSource(); });
        };
    }
    /**
     * Loads the given entropy sources. Returns a function that collects the entropy components.
     *
     * The result is returned synchronously in order to allow start getting the components
     * before the sources are loaded completely.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function loadSources(sources, sourceOptions, excludeSources, loopReleaseInterval) {
        var includedSources = Object.keys(sources).filter(function (sourceKey) { return excludes(excludeSources, sourceKey); });
        // Using `mapWithBreaks` allows asynchronous sources to complete between synchronous sources
        // and measure the duration correctly
        var sourceGettersPromise = suppressUnhandledRejectionWarning(mapWithBreaks(includedSources, function (sourceKey) { return loadSource(sources[sourceKey], sourceOptions); }, loopReleaseInterval));
        return function getComponents() {
            return __awaiter(this, void 0, void 0, function () {
                var sourceGetters, componentPromises, componentArray, components, index;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0: return [4 /*yield*/, sourceGettersPromise];
                        case 1:
                            sourceGetters = _a.sent();
                            return [4 /*yield*/, mapWithBreaks(sourceGetters, function (sourceGetter) { return suppressUnhandledRejectionWarning(sourceGetter()); }, loopReleaseInterval)];
                        case 2:
                            componentPromises = _a.sent();
                            return [4 /*yield*/, Promise.all(componentPromises)
                                // Keeping the component keys order the same as the source keys order
                            ];
                        case 3:
                            componentArray = _a.sent();
                            components = {};
                            for (index = 0; index < includedSources.length; ++index) {
                                components[includedSources[index]] = componentArray[index];
                            }
                            return [2 /*return*/, components];
                    }
                });
            });
        };
    }
    /**
     * Modifies an entropy source by transforming its returned value with the given function.
     * Keeps the source properties: sync/async, 1/2 stages.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function transformSource(source, transformValue) {
        var transformLoadResult = function (loadResult) {
            if (isFinalResultLoaded(loadResult)) {
                return transformValue(loadResult);
            }
            return function () {
                var getResult = loadResult();
                if (isPromise(getResult)) {
                    return getResult.then(transformValue);
                }
                return transformValue(getResult);
            };
        };
        return function (options) {
            var loadResult = source(options);
            if (isPromise(loadResult)) {
                return loadResult.then(transformLoadResult);
            }
            return transformLoadResult(loadResult);
        };
    }

    /*
     * Functions to help with features that vary through browsers
     */
    /**
     * Checks whether the browser is based on Trident (the Internet Explorer engine) without using user-agent.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isTrident() {
        var w = window;
        var n = navigator;
        // The properties are checked to be in IE 10, IE 11 and not to be in other browsers in October 2020
        return (countTruthy([
            'MSCSSMatrix' in w,
            'msSetImmediate' in w,
            'msIndexedDB' in w,
            'msMaxTouchPoints' in n,
            'msPointerEnabled' in n,
        ]) >= 4);
    }
    /**
     * Checks whether the browser is based on EdgeHTML (the pre-Chromium Edge engine) without using user-agent.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isEdgeHTML() {
        // Based on research in October 2020
        var w = window;
        var n = navigator;
        return (countTruthy(['msWriteProfilerMark' in w, 'MSStream' in w, 'msLaunchUri' in n, 'msSaveBlob' in n]) >= 3 &&
            !isTrident());
    }
    /**
     * Checks whether the browser is based on Chromium without using user-agent.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isChromium() {
        // Based on research in October 2020. Tested to detect Chromium 42-86.
        var w = window;
        var n = navigator;
        return (countTruthy([
            'webkitPersistentStorage' in n,
            'webkitTemporaryStorage' in n,
            n.vendor.indexOf('Google') === 0,
            'webkitResolveLocalFileSystemURL' in w,
            'BatteryManager' in w,
            'webkitMediaStream' in w,
            'webkitSpeechGrammar' in w,
        ]) >= 5);
    }
    /**
     * Checks whether the browser is based on mobile or desktop Safari without using user-agent.
     * All iOS browsers use WebKit (the Safari engine).
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isWebKit() {
        // Based on research in August 2024
        var w = window;
        var n = navigator;
        return (countTruthy([
            'ApplePayError' in w,
            'CSSPrimitiveValue' in w,
            'Counter' in w,
            n.vendor.indexOf('Apple') === 0,
            'RGBColor' in w,
            'WebKitMediaKeys' in w,
        ]) >= 4);
    }
    /**
     * Checks whether this WebKit browser is a desktop browser.
     * It doesn't check that the browser is based on WebKit, there is a separate function for this.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isDesktopWebKit() {
        // Checked in Safari and DuckDuckGo
        var w = window;
        var HTMLElement = w.HTMLElement, Document = w.Document;
        return (countTruthy([
            'safari' in w,
            !('ongestureend' in w),
            !('TouchEvent' in w),
            !('orientation' in w),
            HTMLElement && !('autocapitalize' in HTMLElement.prototype),
            Document && 'pointerLockElement' in Document.prototype,
        ]) >= 4);
    }
    /**
     * Checks whether this WebKit browser is Safari.
     * It doesn't check that the browser is based on WebKit, there is a separate function for this.
     *
     * Warning! The function works properly only for Safari version 15.4 and newer.
     */
    function isSafariWebKit() {
        // Checked in Safari, Chrome, Firefox, Yandex, UC Browser, Opera, Edge and DuckDuckGo.
        // iOS Safari and Chrome were checked on iOS 11-18. DuckDuckGo was checked on iOS 17-18 and macOS 14-15.
        // Desktop Safari versions 12-18 were checked.
        // The other browsers were checked on iOS 17 and 18; there was no chance to check them on the other OS versions.
        var w = window;
        return (
        // Filters-out Chrome, Yandex, DuckDuckGo (macOS and iOS), Edge
        isFunctionNative(w.print) &&
            // Doesn't work in Safari < 15.4
            String(w.browser) === '[object WebPageNamespace]');
    }
    /**
     * Checks whether the browser is based on Gecko (Firefox engine) without using user-agent.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isGecko() {
        var _a, _b;
        var w = window;
        // Based on research in September 2020
        return (countTruthy([
            'buildID' in navigator,
            'MozAppearance' in ((_b = (_a = document.documentElement) === null || _a === void 0 ? void 0 : _a.style) !== null && _b !== void 0 ? _b : {}),
            'onmozfullscreenchange' in w,
            'mozInnerScreenX' in w,
            'CSSMozDocumentRule' in w,
            'CanvasCaptureMediaStream' in w,
        ]) >= 4);
    }
    /**
     * Checks whether the browser is based on Chromium version ≥86 without using user-agent.
     * It doesn't check that the browser is based on Chromium, there is a separate function for this.
     */
    function isChromium86OrNewer() {
        // Checked in Chrome 85 vs Chrome 86 both on desktop and Android. Checked in macOS Chrome 128, Android Chrome 127.
        var w = window;
        return (countTruthy([
            !('MediaSettingsRange' in w),
            'RTCEncodedAudioFrame' in w,
            '' + w.Intl === '[object Intl]',
            '' + w.Reflect === '[object Reflect]',
        ]) >= 3);
    }
    /**
     * Checks whether the browser is based on Chromium version ≥122 without using user-agent.
     * It doesn't check that the browser is based on Chromium, there is a separate function for this.
     */
    function isChromium122OrNewer() {
        // Checked in Chrome 121 vs Chrome 122 and 129 both on desktop and Android
        var w = window;
        var URLPattern = w.URLPattern;
        return (countTruthy([
            'union' in Set.prototype,
            'Iterator' in w,
            URLPattern && 'hasRegExpGroups' in URLPattern.prototype,
            'RGB8' in WebGLRenderingContext.prototype,
        ]) >= 3);
    }
    /**
     * Checks whether the browser is based on WebKit version ≥606 (Safari ≥12) without using user-agent.
     * It doesn't check that the browser is based on WebKit, there is a separate function for this.
     *
     * @see https://en.wikipedia.org/wiki/Safari_version_history#Release_history Safari-WebKit versions map
     */
    function isWebKit606OrNewer() {
        // Checked in Safari 9–18
        var w = window;
        return (countTruthy([
            'DOMRectList' in w,
            'RTCPeerConnectionIceEvent' in w,
            'SVGGeometryElement' in w,
            'ontransitioncancel' in w,
        ]) >= 3);
    }
    /**
     * Checks whether the browser is based on WebKit version ≥616 (Safari ≥17) without using user-agent.
     * It doesn't check that the browser is based on WebKit, there is a separate function for this.
     *
     * @see https://developer.apple.com/documentation/safari-release-notes/safari-17-release-notes Safari 17 release notes
     * @see https://tauri.app/v1/references/webview-versions/#webkit-versions-in-safari Safari-WebKit versions map
     */
    function isWebKit616OrNewer() {
        var w = window;
        var n = navigator;
        var CSS = w.CSS, HTMLButtonElement = w.HTMLButtonElement;
        return (countTruthy([
            !('getStorageUpdates' in n),
            HTMLButtonElement && 'popover' in HTMLButtonElement.prototype,
            'CSSCounterStyleRule' in w,
            CSS.supports('font-size-adjust: ex-height 0.5'),
            CSS.supports('text-transform: full-width'),
        ]) >= 4);
    }
    /**
     * Checks whether the device is an iPad.
     * It doesn't check that the engine is WebKit and that the WebKit isn't desktop.
     */
    function isIPad() {
        // Checked on:
        // Safari on iPadOS (both mobile and desktop modes): 8, 11-18
        // Chrome on iPadOS (both mobile and desktop modes): 11-18
        // Safari on iOS (both mobile and desktop modes): 9-18
        // Chrome on iOS (both mobile and desktop modes): 9-18
        // Before iOS 13. Safari tampers the value in "request desktop site" mode since iOS 13.
        if (navigator.platform === 'iPad') {
            return true;
        }
        var s = screen;
        var screenRatio = s.width / s.height;
        return (countTruthy([
            // Since iOS 13. Doesn't work in Chrome on iPadOS <15, but works in desktop mode.
            'MediaSource' in window,
            // Since iOS 12. Doesn't work in Chrome on iPadOS.
            !!Element.prototype.webkitRequestFullscreen,
            // iPhone 4S that runs iOS 9 matches this, but it is not supported
            // Doesn't work in incognito mode of Safari ≥17 with split screen because of tracking prevention
            screenRatio > 0.65 && screenRatio < 1.53,
        ]) >= 2);
    }
    /**
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getFullscreenElement() {
        var d = document;
        return d.fullscreenElement || d.msFullscreenElement || d.mozFullScreenElement || d.webkitFullscreenElement || null;
    }
    function exitFullscreen() {
        var d = document;
        // `call` is required because the function throws an error without a proper "this" context
        return (d.exitFullscreen || d.msExitFullscreen || d.mozCancelFullScreen || d.webkitExitFullscreen).call(d);
    }
    /**
     * Checks whether the device runs on Android without using user-agent.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isAndroid() {
        var isItChromium = isChromium();
        var isItGecko = isGecko();
        var w = window;
        var n = navigator;
        var c = 'connection';
        // Chrome removes all words "Android" from `navigator` when desktop version is requested
        // Firefox keeps "Android" in `navigator.appVersion` when desktop version is requested
        if (isItChromium) {
            return (countTruthy([
                !('SharedWorker' in w),
                // `typechange` is deprecated, but it's still present on Android (tested on Chrome Mobile 117)
                // Removal proposal https://bugs.chromium.org/p/chromium/issues/detail?id=699892
                // Note: this expression returns true on ChromeOS, so additional detectors are required to avoid false-positives
                n[c] && 'ontypechange' in n[c],
                !('sinkId' in new Audio()),
            ]) >= 2);
        }
        else if (isItGecko) {
            return countTruthy(['onorientationchange' in w, 'orientation' in w, /android/i.test(n.appVersion)]) >= 2;
        }
        else {
            // Only 2 browser engines are presented on Android.
            // Actually, there is also Android 4.1 browser, but it's not worth detecting it at the moment.
            return false;
        }
    }
    /**
     * Checks whether the browser is Samsung Internet without using user-agent.
     * It doesn't check that the browser is based on Chromium, please use `isChromium` before using this function.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function isSamsungInternet() {
        // Checked in Samsung Internet 21, 25 and 27
        var n = navigator;
        var w = window;
        var audioPrototype = Audio.prototype;
        var visualViewport = w.visualViewport;
        return (countTruthy([
            'srLatency' in audioPrototype,
            'srChannelCount' in audioPrototype,
            'devicePosture' in n,
            visualViewport && 'segments' in visualViewport,
            'getTextInformation' in Image.prototype, // Not available in Samsung Internet 21
        ]) >= 3);
    }

    /**
     * A deep description: https://fingerprint.com/blog/audio-fingerprinting/
     * Inspired by and based on https://github.com/cozylife/audio-fingerprint
     *
     * A version of the entropy source with stabilization to make it suitable for static fingerprinting.
     * Audio signal is noised in private mode of Safari 17, so audio fingerprinting is skipped in Safari 17.
     */
    function getAudioFingerprint() {
        if (doesBrowserPerformAntifingerprinting$1()) {
            return -4 /* SpecialFingerprint.KnownForAntifingerprinting */;
        }
        return getUnstableAudioFingerprint();
    }
    /**
     * A version of the entropy source without stabilization.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getUnstableAudioFingerprint() {
        var w = window;
        var AudioContext = w.OfflineAudioContext || w.webkitOfflineAudioContext;
        if (!AudioContext) {
            return -2 /* SpecialFingerprint.NotSupported */;
        }
        // In some browsers, audio context always stays suspended unless the context is started in response to a user action
        // (e.g. a click or a tap). It prevents audio fingerprint from being taken at an arbitrary moment of time.
        // Such browsers are old and unpopular, so the audio fingerprinting is just skipped in them.
        // See a similar case explanation at https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088
        if (doesBrowserSuspendAudioContext()) {
            return -1 /* SpecialFingerprint.KnownForSuspending */;
        }
        var hashFromIndex = 4500;
        var hashToIndex = 5000;
        var context = new AudioContext(1, hashToIndex, 44100);
        var oscillator = context.createOscillator();
        oscillator.type = 'triangle';
        oscillator.frequency.value = 10000;
        var compressor = context.createDynamicsCompressor();
        compressor.threshold.value = -50;
        compressor.knee.value = 40;
        compressor.ratio.value = 12;
        compressor.attack.value = 0;
        compressor.release.value = 0.25;
        oscillator.connect(compressor);
        compressor.connect(context.destination);
        oscillator.start(0);
        var _a = startRenderingAudio(context), renderPromise = _a[0], finishRendering = _a[1];
        // Suppresses the console error message in case when the fingerprint fails before requested
        var fingerprintPromise = suppressUnhandledRejectionWarning(renderPromise.then(function (buffer) { return getHash(buffer.getChannelData(0).subarray(hashFromIndex)); }, function (error) {
            if (error.name === "timeout" /* InnerErrorName.Timeout */ || error.name === "suspended" /* InnerErrorName.Suspended */) {
                return -3 /* SpecialFingerprint.Timeout */;
            }
            throw error;
        }));
        return function () {
            finishRendering();
            return fingerprintPromise;
        };
    }
    /**
     * Checks if the current browser is known for always suspending audio context
     */
    function doesBrowserSuspendAudioContext() {
        // Mobile Safari 11 and older
        return isWebKit() && !isDesktopWebKit() && !isWebKit606OrNewer();
    }
    /**
     * Checks if the current browser is known for applying anti-fingerprinting measures in all or some critical modes
     */
    function doesBrowserPerformAntifingerprinting$1() {
        return (
        // Safari ≥17
        (isWebKit() && isWebKit616OrNewer() && isSafariWebKit()) ||
            // Samsung Internet ≥26
            (isChromium() && isSamsungInternet() && isChromium122OrNewer()));
    }
    /**
     * Starts rendering the audio context.
     * When the returned function is called, the render process starts finishing.
     */
    function startRenderingAudio(context) {
        var renderTryMaxCount = 3;
        var renderRetryDelay = 500;
        var runningMaxAwaitTime = 500;
        var runningSufficientTime = 5000;
        var finalize = function () { return undefined; };
        var resultPromise = new Promise(function (resolve, reject) {
            var isFinalized = false;
            var renderTryCount = 0;
            var startedRunningAt = 0;
            context.oncomplete = function (event) { return resolve(event.renderedBuffer); };
            var startRunningTimeout = function () {
                setTimeout(function () { return reject(makeInnerError("timeout" /* InnerErrorName.Timeout */)); }, Math.min(runningMaxAwaitTime, startedRunningAt + runningSufficientTime - Date.now()));
            };
            var tryRender = function () {
                try {
                    var renderingPromise = context.startRendering();
                    // `context.startRendering` has two APIs: Promise and callback, we check that it's really a promise just in case
                    if (isPromise(renderingPromise)) {
                        // Suppresses all unhandled rejections in case of scheduled redundant retries after successful rendering
                        suppressUnhandledRejectionWarning(renderingPromise);
                    }
                    switch (context.state) {
                        case 'running':
                            startedRunningAt = Date.now();
                            if (isFinalized) {
                                startRunningTimeout();
                            }
                            break;
                        // Sometimes the audio context doesn't start after calling `startRendering` (in addition to the cases where
                        // audio context doesn't start at all). A known case is starting an audio context when the browser tab is in
                        // background on iPhone. Retries usually help in this case.
                        case 'suspended':
                            // The audio context can reject starting until the tab is in foreground. Long fingerprint duration
                            // in background isn't a problem, therefore the retry attempts don't count in background. It can lead to
                            // a situation when a fingerprint takes very long time and finishes successfully. FYI, the audio context
                            // can be suspended when `document.hidden === false` and start running after a retry.
                            if (!document.hidden) {
                                renderTryCount++;
                            }
                            if (isFinalized && renderTryCount >= renderTryMaxCount) {
                                reject(makeInnerError("suspended" /* InnerErrorName.Suspended */));
                            }
                            else {
                                setTimeout(tryRender, renderRetryDelay);
                            }
                            break;
                    }
                }
                catch (error) {
                    reject(error);
                }
            };
            tryRender();
            finalize = function () {
                if (!isFinalized) {
                    isFinalized = true;
                    if (startedRunningAt > 0) {
                        startRunningTimeout();
                    }
                }
            };
        });
        return [resultPromise, finalize];
    }
    function getHash(signal) {
        var hash = 0;
        for (var i = 0; i < signal.length; ++i) {
            hash += Math.abs(signal[i]);
        }
        return hash;
    }
    function makeInnerError(name) {
        var error = new Error(name);
        error.name = name;
        return error;
    }

    /**
     * Creates and keeps an invisible iframe while the given function runs.
     * The given function is called when the iframe is loaded and has a body.
     * The iframe allows to measure DOM sizes inside itself.
     *
     * Notice: passing an initial HTML code doesn't work in IE.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function withIframe(action, initialHtml, domPollInterval) {
        var _a, _b, _c;
        if (domPollInterval === void 0) { domPollInterval = 50; }
        return __awaiter(this, void 0, void 0, function () {
            var d, iframe;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        d = document;
                        _d.label = 1;
                    case 1:
                        if (!!d.body) return [3 /*break*/, 3];
                        return [4 /*yield*/, wait(domPollInterval)];
                    case 2:
                        _d.sent();
                        return [3 /*break*/, 1];
                    case 3:
                        iframe = d.createElement('iframe');
                        _d.label = 4;
                    case 4:
                        _d.trys.push([4, , 10, 11]);
                        return [4 /*yield*/, new Promise(function (_resolve, _reject) {
                                var isComplete = false;
                                var resolve = function () {
                                    isComplete = true;
                                    _resolve();
                                };
                                var reject = function (error) {
                                    isComplete = true;
                                    _reject(error);
                                };
                                iframe.onload = resolve;
                                iframe.onerror = reject;
                                var style = iframe.style;
                                style.setProperty('display', 'block', 'important'); // Required for browsers to calculate the layout
                                style.position = 'absolute';
                                style.top = '0';
                                style.left = '0';
                                style.visibility = 'hidden';
                                if (initialHtml && 'srcdoc' in iframe) {
                                    iframe.srcdoc = initialHtml;
                                }
                                else {
                                    iframe.src = 'about:blank';
                                }
                                d.body.appendChild(iframe);
                                // WebKit in WeChat doesn't fire the iframe's `onload` for some reason.
                                // This code checks for the loading state manually.
                                // See https://github.com/fingerprintjs/fingerprintjs/issues/645
                                var checkReadyState = function () {
                                    var _a, _b;
                                    // The ready state may never become 'complete' in Firefox despite the 'load' event being fired.
                                    // So an infinite setTimeout loop can happen without this check.
                                    // See https://github.com/fingerprintjs/fingerprintjs/pull/716#issuecomment-986898796
                                    if (isComplete) {
                                        return;
                                    }
                                    // Make sure iframe.contentWindow and iframe.contentWindow.document are both loaded
                                    // The contentWindow.document can miss in JSDOM (https://github.com/jsdom/jsdom).
                                    if (((_b = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document) === null || _b === void 0 ? void 0 : _b.readyState) === 'complete') {
                                        resolve();
                                    }
                                    else {
                                        setTimeout(checkReadyState, 10);
                                    }
                                };
                                checkReadyState();
                            })];
                    case 5:
                        _d.sent();
                        _d.label = 6;
                    case 6:
                        if (!!((_b = (_a = iframe.contentWindow) === null || _a === void 0 ? void 0 : _a.document) === null || _b === void 0 ? void 0 : _b.body)) return [3 /*break*/, 8];
                        return [4 /*yield*/, wait(domPollInterval)];
                    case 7:
                        _d.sent();
                        return [3 /*break*/, 6];
                    case 8: return [4 /*yield*/, action(iframe, iframe.contentWindow)];
                    case 9: return [2 /*return*/, _d.sent()];
                    case 10:
                        (_c = iframe.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(iframe);
                        return [7 /*endfinally*/];
                    case 11: return [2 /*return*/];
                }
            });
        });
    }
    /**
     * Creates a DOM element that matches the given selector.
     * Only single element selector are supported (without operators like space, +, >, etc).
     */
    function selectorToElement(selector) {
        var _a = parseSimpleCssSelector(selector), tag = _a[0], attributes = _a[1];
        var element = document.createElement(tag !== null && tag !== void 0 ? tag : 'div');
        for (var _i = 0, _b = Object.keys(attributes); _i < _b.length; _i++) {
            var name_1 = _b[_i];
            var value = attributes[name_1].join(' ');
            // Changing the `style` attribute can cause a CSP error, therefore we change the `style.cssText` property.
            // https://github.com/fingerprintjs/fingerprintjs/issues/733
            if (name_1 === 'style') {
                addStyleString(element.style, value);
            }
            else {
                element.setAttribute(name_1, value);
            }
        }
        return element;
    }
    /**
     * Adds CSS styles from a string in such a way that doesn't trigger a CSP warning (unsafe-inline or unsafe-eval)
     */
    function addStyleString(style, source) {
        // We don't use `style.cssText` because browsers must block it when no `unsafe-eval` CSP is presented: https://csplite.com/csp145/#w3c_note
        // Even though the browsers ignore this standard, we don't use `cssText` just in case.
        for (var _i = 0, _a = source.split(';'); _i < _a.length; _i++) {
            var property = _a[_i];
            var match = /^\s*([\w-]+)\s*:\s*(.+?)(\s*!([\w-]+))?\s*$/.exec(property);
            if (match) {
                var name_2 = match[1], value = match[2], priority = match[4];
                style.setProperty(name_2, value, priority || ''); // The last argument can't be undefined in IE11
            }
        }
    }
    /**
     * Returns true if the code runs in an iframe, and any parent page's origin doesn't match the current origin
     */
    function isAnyParentCrossOrigin() {
        var currentWindow = window;
        for (;;) {
            var parentWindow = currentWindow.parent;
            if (!parentWindow || parentWindow === currentWindow) {
                return false; // The top page is reached
            }
            try {
                if (parentWindow.location.origin !== currentWindow.location.origin) {
                    return true;
                }
            }
            catch (error) {
                // The error is thrown when `origin` is accessed on `parentWindow.location` when the parent is cross-origin
                if (error instanceof Error && error.name === 'SecurityError') {
                    return true;
                }
                throw error;
            }
            currentWindow = parentWindow;
        }
    }

    // We use m or w because these two characters take up the maximum width.
    // And we use a LLi so that the same matching fonts can get separated.
    var testString = 'mmMwWLliI0O&1';
    // We test using 48px font size, we may use any size. I guess larger the better.
    var textSize = '48px';
    // A font will be compared against all the three default fonts.
    // And if for any default fonts it doesn't match, then that font is available.
    var baseFonts = ['monospace', 'sans-serif', 'serif'];
    var fontList = [
        // This is android-specific font from "Roboto" family
        'sans-serif-thin',
        'ARNO PRO',
        'Agency FB',
        'Arabic Typesetting',
        'Arial Unicode MS',
        'AvantGarde Bk BT',
        'BankGothic Md BT',
        'Batang',
        'Bitstream Vera Sans Mono',
        'Calibri',
        'Century',
        'Century Gothic',
        'Clarendon',
        'EUROSTILE',
        'Franklin Gothic',
        'Futura Bk BT',
        'Futura Md BT',
        'GOTHAM',
        'Gill Sans',
        'HELV',
        'Haettenschweiler',
        'Helvetica Neue',
        'Humanst521 BT',
        'Leelawadee',
        'Letter Gothic',
        'Levenim MT',
        'Lucida Bright',
        'Lucida Sans',
        'Menlo',
        'MS Mincho',
        'MS Outlook',
        'MS Reference Specialty',
        'MS UI Gothic',
        'MT Extra',
        'MYRIAD PRO',
        'Marlett',
        'Meiryo UI',
        'Microsoft Uighur',
        'Minion Pro',
        'Monotype Corsiva',
        'PMingLiU',
        'Pristina',
        'SCRIPTINA',
        'Segoe UI Light',
        'Serifa',
        'SimHei',
        'Small Fonts',
        'Staccato222 BT',
        'TRAJAN PRO',
        'Univers CE 55 Medium',
        'Vrinda',
        'ZWAdobeF',
    ];
    // kudos to http://www.lalit.org/lab/javascript-css-font-detect/
    function getFonts() {
        var _this = this;
        // Running the script in an iframe makes it not affect the page look and not be affected by the page CSS. See:
        // https://github.com/fingerprintjs/fingerprintjs/issues/592
        // https://github.com/fingerprintjs/fingerprintjs/issues/628
        return withIframe(function (_, _a) {
            var document = _a.document;
            return __awaiter(_this, void 0, void 0, function () {
                var holder, spansContainer, defaultWidth, defaultHeight, createSpan, createSpanWithFonts, initializeBaseFontsSpans, initializeFontsSpans, isFontAvailable, baseFontsSpans, fontsSpans, index;
                return __generator(this, function (_b) {
                    holder = document.body;
                    holder.style.fontSize = textSize;
                    spansContainer = document.createElement('div');
                    spansContainer.style.setProperty('visibility', 'hidden', 'important');
                    defaultWidth = {};
                    defaultHeight = {};
                    createSpan = function (fontFamily) {
                        var span = document.createElement('span');
                        var style = span.style;
                        style.position = 'absolute';
                        style.top = '0';
                        style.left = '0';
                        style.fontFamily = fontFamily;
                        span.textContent = testString;
                        spansContainer.appendChild(span);
                        return span;
                    };
                    createSpanWithFonts = function (fontToDetect, baseFont) {
                        return createSpan("'".concat(fontToDetect, "',").concat(baseFont));
                    };
                    initializeBaseFontsSpans = function () {
                        return baseFonts.map(createSpan);
                    };
                    initializeFontsSpans = function () {
                        // Stores {fontName : [spans for that font]}
                        var spans = {};
                        var _loop_1 = function (font) {
                            spans[font] = baseFonts.map(function (baseFont) { return createSpanWithFonts(font, baseFont); });
                        };
                        for (var _i = 0, fontList_1 = fontList; _i < fontList_1.length; _i++) {
                            var font = fontList_1[_i];
                            _loop_1(font);
                        }
                        return spans;
                    };
                    isFontAvailable = function (fontSpans) {
                        return baseFonts.some(function (baseFont, baseFontIndex) {
                            return fontSpans[baseFontIndex].offsetWidth !== defaultWidth[baseFont] ||
                                fontSpans[baseFontIndex].offsetHeight !== defaultHeight[baseFont];
                        });
                    };
                    baseFontsSpans = initializeBaseFontsSpans();
                    fontsSpans = initializeFontsSpans();
                    // add all the spans to the DOM
                    holder.appendChild(spansContainer);
                    // get the default width for the three base fonts
                    for (index = 0; index < baseFonts.length; index++) {
                        defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth; // width for the default font
                        defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight; // height for the default font
                    }
                    // check available fonts
                    return [2 /*return*/, fontList.filter(function (font) { return isFontAvailable(fontsSpans[font]); })];
                });
            });
        });
    }

    function getPlugins() {
        var rawPlugins = navigator.plugins;
        if (!rawPlugins) {
            return undefined;
        }
        var plugins = [];
        // Safari 10 doesn't support iterating navigator.plugins with for...of
        for (var i = 0; i < rawPlugins.length; ++i) {
            var plugin = rawPlugins[i];
            if (!plugin) {
                continue;
            }
            var mimeTypes = [];
            for (var j = 0; j < plugin.length; ++j) {
                var mimeType = plugin[j];
                mimeTypes.push({
                    type: mimeType.type,
                    suffixes: mimeType.suffixes,
                });
            }
            plugins.push({
                name: plugin.name,
                description: plugin.description,
                mimeTypes: mimeTypes,
            });
        }
        return plugins;
    }

    /**
     * @see https://www.browserleaks.com/canvas#how-does-it-work
     *
     * A version of the entropy source with stabilization to make it suitable for static fingerprinting.
     * Canvas image is noised in private mode of Safari 17, so image rendering is skipped in Safari 17.
     */
    function getCanvasFingerprint() {
        return getUnstableCanvasFingerprint(doesBrowserPerformAntifingerprinting());
    }
    /**
     * A version of the entropy source without stabilization.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getUnstableCanvasFingerprint(skipImages) {
        var _a;
        var winding = false;
        var geometry;
        var text;
        var _b = makeCanvasContext(), canvas = _b[0], context = _b[1];
        if (!isSupported(canvas, context)) {
            geometry = text = "unsupported" /* ImageStatus.Unsupported */;
        }
        else {
            winding = doesSupportWinding(context);
            if (skipImages) {
                geometry = text = "skipped" /* ImageStatus.Skipped */;
            }
            else {
                _a = renderImages(canvas, context), geometry = _a[0], text = _a[1];
            }
        }
        return { winding: winding, geometry: geometry, text: text };
    }
    function makeCanvasContext() {
        var canvas = document.createElement('canvas');
        canvas.width = 1;
        canvas.height = 1;
        return [canvas, canvas.getContext('2d')];
    }
    function isSupported(canvas, context) {
        return !!(context && canvas.toDataURL);
    }
    function doesSupportWinding(context) {
        // https://web.archive.org/web/20170825024655/http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
        // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js
        context.rect(0, 0, 10, 10);
        context.rect(2, 2, 6, 6);
        return !context.isPointInPath(5, 5, 'evenodd');
    }
    function renderImages(canvas, context) {
        renderTextImage(canvas, context);
        var textImage1 = canvasToString(canvas);
        var textImage2 = canvasToString(canvas); // It's slightly faster to double-encode the text image
        // Some browsers add a noise to the canvas: https://github.com/fingerprintjs/fingerprintjs/issues/791
        // The canvas is excluded from the fingerprint in this case
        if (textImage1 !== textImage2) {
            return ["unstable" /* ImageStatus.Unstable */, "unstable" /* ImageStatus.Unstable */];
        }
        // Text is unstable:
        // https://github.com/fingerprintjs/fingerprintjs/issues/583
        // https://github.com/fingerprintjs/fingerprintjs/issues/103
        // Therefore it's extracted into a separate image.
        renderGeometryImage(canvas, context);
        var geometryImage = canvasToString(canvas);
        return [geometryImage, textImage1];
    }
    function renderTextImage(canvas, context) {
        // Resizing the canvas cleans it
        canvas.width = 240;
        canvas.height = 60;
        context.textBaseline = 'alphabetic';
        context.fillStyle = '#f60';
        context.fillRect(100, 1, 62, 20);
        context.fillStyle = '#069';
        // It's important to use explicit built-in fonts in order to exclude the affect of font preferences
        // (there is a separate entropy source for them).
        context.font = '11pt "Times New Roman"';
        // The choice of emojis has a gigantic impact on rendering performance (especially in FF).
        // Some newer emojis cause it to slow down 50-200 times.
        // There must be no text to the right of the emoji, see https://github.com/fingerprintjs/fingerprintjs/issues/574
        // A bare emoji shouldn't be used because the canvas will change depending on the script encoding:
        // https://github.com/fingerprintjs/fingerprintjs/issues/66
        // Escape sequence shouldn't be used too because Terser will turn it into a bare unicode.
        var printedText = "Cwm fjordbank gly ".concat(String.fromCharCode(55357, 56835) /* 😃 */);
        context.fillText(printedText, 2, 15);
        context.fillStyle = 'rgba(102, 204, 0, 0.2)';
        context.font = '18pt Arial';
        context.fillText(printedText, 4, 45);
    }
    function renderGeometryImage(canvas, context) {
        // Resizing the canvas cleans it
        canvas.width = 122;
        canvas.height = 110;
        // Canvas blending
        // https://web.archive.org/web/20170826194121/http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/
        // http://jsfiddle.net/NDYV8/16/
        context.globalCompositeOperation = 'multiply';
        for (var _i = 0, _a = [
            ['#f2f', 40, 40],
            ['#2ff', 80, 40],
            ['#ff2', 60, 80],
        ]; _i < _a.length; _i++) {
            var _b = _a[_i], color = _b[0], x = _b[1], y = _b[2];
            context.fillStyle = color;
            context.beginPath();
            context.arc(x, y, 40, 0, Math.PI * 2, true);
            context.closePath();
            context.fill();
        }
        // Canvas winding
        // https://web.archive.org/web/20130913061632/http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/
        // http://jsfiddle.net/NDYV8/19/
        context.fillStyle = '#f9c';
        context.arc(60, 60, 60, 0, Math.PI * 2, true);
        context.arc(60, 60, 20, 0, Math.PI * 2, true);
        context.fill('evenodd');
    }
    function canvasToString(canvas) {
        return canvas.toDataURL();
    }
    /**
     * Checks if the current browser is known for applying anti-fingerprinting measures in all or some critical modes
     */
    function doesBrowserPerformAntifingerprinting() {
        // Safari 17
        return isWebKit() && isWebKit616OrNewer() && isSafariWebKit();
    }

    /**
     * This is a crude and primitive touch screen detection. It's not possible to currently reliably detect the availability
     * of a touch screen with a JS, without actually subscribing to a touch event.
     *
     * @see http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
     * @see https://github.com/Modernizr/Modernizr/issues/548
     */
    function getTouchSupport() {
        var n = navigator;
        var maxTouchPoints = 0;
        var touchEvent;
        if (n.maxTouchPoints !== undefined) {
            maxTouchPoints = toInt(n.maxTouchPoints);
        }
        else if (n.msMaxTouchPoints !== undefined) {
            maxTouchPoints = n.msMaxTouchPoints;
        }
        try {
            document.createEvent('TouchEvent');
            touchEvent = true;
        }
        catch (_a) {
            touchEvent = false;
        }
        var touchStart = 'ontouchstart' in window;
        return {
            maxTouchPoints: maxTouchPoints,
            touchEvent: touchEvent,
            touchStart: touchStart,
        };
    }

    function getOsCpu() {
        return navigator.oscpu;
    }

    function getLanguages() {
        var n = navigator;
        var result = [];
        var language = n.language || n.userLanguage || n.browserLanguage || n.systemLanguage;
        if (language !== undefined) {
            result.push([language]);
        }
        if (Array.isArray(n.languages)) {
            // Starting from Chromium 86, there is only a single value in `navigator.language` in Incognito mode:
            // the value of `navigator.language`. Therefore the value is ignored in this browser.
            if (!(isChromium() && isChromium86OrNewer())) {
                result.push(n.languages);
            }
        }
        else if (typeof n.languages === 'string') {
            var languages = n.languages;
            if (languages) {
                result.push(languages.split(','));
            }
        }
        return result;
    }

    function getColorDepth() {
        return window.screen.colorDepth;
    }

    function getDeviceMemory() {
        // `navigator.deviceMemory` is a string containing a number in some unidentified cases
        return replaceNaN(toFloat(navigator.deviceMemory), undefined);
    }

    /**
     * A version of the entropy source with stabilization to make it suitable for static fingerprinting.
     * The window resolution is always the document size in private mode of Safari 17,
     * so the window resolution is not used in Safari 17.
     */
    function getScreenResolution() {
        if (isWebKit() && isWebKit616OrNewer() && isSafariWebKit()) {
            return undefined;
        }
        return getUnstableScreenResolution();
    }
    /**
     * A version of the entropy source without stabilization.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getUnstableScreenResolution() {
        var s = screen;
        // Some browsers return screen resolution as strings, e.g. "1200", instead of a number, e.g. 1200.
        // I suspect it's done by certain plugins that randomize browser properties to prevent fingerprinting.
        // Some browsers even return  screen resolution as not numbers.
        var parseDimension = function (value) { return replaceNaN(toInt(value), null); };
        var dimensions = [parseDimension(s.width), parseDimension(s.height)];
        dimensions.sort().reverse();
        return dimensions;
    }

    var screenFrameCheckInterval = 2500;
    var roundingPrecision = 10;
    // The type is readonly to protect from unwanted mutations
    var screenFrameBackup;
    var screenFrameSizeTimeoutId;
    /**
     * Starts watching the screen frame size. When a non-zero size appears, the size is saved and the watch is stopped.
     * Later, when `getScreenFrame` runs, it will return the saved non-zero size if the current size is null.
     *
     * This trick is required to mitigate the fact that the screen frame turns null in some cases.
     * See more on this at https://github.com/fingerprintjs/fingerprintjs/issues/568
     */
    function watchScreenFrame() {
        if (screenFrameSizeTimeoutId !== undefined) {
            return;
        }
        var checkScreenFrame = function () {
            var frameSize = getCurrentScreenFrame();
            if (isFrameSizeNull(frameSize)) {
                screenFrameSizeTimeoutId = setTimeout(checkScreenFrame, screenFrameCheckInterval);
            }
            else {
                screenFrameBackup = frameSize;
                screenFrameSizeTimeoutId = undefined;
            }
        };
        checkScreenFrame();
    }
    /**
     * A version of the entropy source without stabilization.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getUnstableScreenFrame() {
        var _this = this;
        watchScreenFrame();
        return function () { return __awaiter(_this, void 0, void 0, function () {
            var frameSize;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        frameSize = getCurrentScreenFrame();
                        if (!isFrameSizeNull(frameSize)) return [3 /*break*/, 2];
                        if (screenFrameBackup) {
                            return [2 /*return*/, __spreadArray([], screenFrameBackup, true)];
                        }
                        if (!getFullscreenElement()) return [3 /*break*/, 2];
                        // Some browsers set the screen frame to zero when programmatic fullscreen is on.
                        // There is a chance of getting a non-zero frame after exiting the fullscreen.
                        // See more on this at https://github.com/fingerprintjs/fingerprintjs/issues/568
                        return [4 /*yield*/, exitFullscreen()];
                    case 1:
                        // Some browsers set the screen frame to zero when programmatic fullscreen is on.
                        // There is a chance of getting a non-zero frame after exiting the fullscreen.
                        // See more on this at https://github.com/fingerprintjs/fingerprintjs/issues/568
                        _a.sent();
                        frameSize = getCurrentScreenFrame();
                        _a.label = 2;
                    case 2:
                        if (!isFrameSizeNull(frameSize)) {
                            screenFrameBackup = frameSize;
                        }
                        return [2 /*return*/, frameSize];
                }
            });
        }); };
    }
    /**
     * A version of the entropy source with stabilization to make it suitable for static fingerprinting.
     *
     * Sometimes the available screen resolution changes a bit, e.g. 1900x1440 → 1900x1439. A possible reason: macOS Dock
     * shrinks to fit more icons when there is too little space. The rounding is used to mitigate the difference.
     *
     * The frame width is always 0 in private mode of Safari 17, so the frame is not used in Safari 17.
     */
    function getScreenFrame() {
        var _this = this;
        if (isWebKit() && isWebKit616OrNewer() && isSafariWebKit()) {
            return function () { return Promise.resolve(undefined); };
        }
        var screenFrameGetter = getUnstableScreenFrame();
        return function () { return __awaiter(_this, void 0, void 0, function () {
            var frameSize, processSize;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0: return [4 /*yield*/, screenFrameGetter()];
                    case 1:
                        frameSize = _a.sent();
                        processSize = function (sideSize) { return (sideSize === null ? null : round(sideSize, roundingPrecision)); };
                        // It might look like I don't know about `for` and `map`.
                        // In fact, such code is used to avoid TypeScript issues without using `as`.
                        return [2 /*return*/, [processSize(frameSize[0]), processSize(frameSize[1]), processSize(frameSize[2]), processSize(frameSize[3])]];
                }
            });
        }); };
    }
    function getCurrentScreenFrame() {
        var s = screen;
        // Some browsers return screen resolution as strings, e.g. "1200", instead of a number, e.g. 1200.
        // I suspect it's done by certain plugins that randomize browser properties to prevent fingerprinting.
        //
        // Some browsers (IE, Edge ≤18) don't provide `screen.availLeft` and `screen.availTop`. The property values are
        // replaced with 0 in such cases to not lose the entropy from `screen.availWidth` and `screen.availHeight`.
        return [
            replaceNaN(toFloat(s.availTop), null),
            replaceNaN(toFloat(s.width) - toFloat(s.availWidth) - replaceNaN(toFloat(s.availLeft), 0), null),
            replaceNaN(toFloat(s.height) - toFloat(s.availHeight) - replaceNaN(toFloat(s.availTop), 0), null),
            replaceNaN(toFloat(s.availLeft), null),
        ];
    }
    function isFrameSizeNull(frameSize) {
        for (var i = 0; i < 4; ++i) {
            if (frameSize[i]) {
                return false;
            }
        }
        return true;
    }

    function getHardwareConcurrency() {
        // sometimes hardware concurrency is a string
        return replaceNaN(toInt(navigator.hardwareConcurrency), undefined);
    }

    function getTimezone() {
        var _a;
        var DateTimeFormat = (_a = window.Intl) === null || _a === void 0 ? void 0 : _a.DateTimeFormat;
        if (DateTimeFormat) {
            var timezone = new DateTimeFormat().resolvedOptions().timeZone;
            if (timezone) {
                return timezone;
            }
        }
        // For browsers that don't support timezone names
        // The minus is intentional because the JS offset is opposite to the real offset
        var offset = -getTimezoneOffset();
        return "UTC".concat(offset >= 0 ? '+' : '').concat(offset);
    }
    function getTimezoneOffset() {
        var currentYear = new Date().getFullYear();
        // The timezone offset may change over time due to daylight saving time (DST) shifts.
        // The non-DST timezone offset is used as the result timezone offset.
        // Since the DST season differs in the northern and the southern hemispheres,
        // both January and July timezones offsets are considered.
        return Math.max(
        // `getTimezoneOffset` returns a number as a string in some unidentified cases
        toFloat(new Date(currentYear, 0, 1).getTimezoneOffset()), toFloat(new Date(currentYear, 6, 1).getTimezoneOffset()));
    }

    function getSessionStorage() {
        try {
            return !!window.sessionStorage;
        }
        catch (error) {
            /* SecurityError when referencing it means it exists */
            return true;
        }
    }

    // https://bugzilla.mozilla.org/show_bug.cgi?id=781447
    function getLocalStorage() {
        try {
            return !!window.localStorage;
        }
        catch (e) {
            /* SecurityError when referencing it means it exists */
            return true;
        }
    }

    function getIndexedDB() {
        // IE and Edge don't allow accessing indexedDB in private mode, therefore IE and Edge will have different
        // visitor identifier in normal and private modes.
        if (isTrident() || isEdgeHTML()) {
            return undefined;
        }
        try {
            return !!window.indexedDB;
        }
        catch (e) {
            /* SecurityError when referencing it means it exists */
            return true;
        }
    }

    function getOpenDatabase() {
        return !!window.openDatabase;
    }

    function getCpuClass() {
        return navigator.cpuClass;
    }

    function getPlatform() {
        // Android Chrome 86 and 87 and Android Firefox 80 and 84 don't mock the platform value when desktop mode is requested
        var platform = navigator.platform;
        // iOS mocks the platform value when desktop version is requested: https://github.com/fingerprintjs/fingerprintjs/issues/514
        // iPad uses desktop mode by default since iOS 13
        // The value is 'MacIntel' on M1 Macs
        // The value is 'iPhone' on iPod Touch
        if (platform === 'MacIntel') {
            if (isWebKit() && !isDesktopWebKit()) {
                return isIPad() ? 'iPad' : 'iPhone';
            }
        }
        return platform;
    }

    function getVendor() {
        return navigator.vendor || '';
    }

    /**
     * Checks for browser-specific (not engine specific) global variables to tell browsers with the same engine apart.
     * Only somewhat popular browsers are considered.
     */
    function getVendorFlavors() {
        var flavors = [];
        for (var _i = 0, _a = [
            // Blink and some browsers on iOS
            'chrome',
            // Safari on macOS
            'safari',
            // Chrome on iOS (checked in 85 on 13 and 87 on 14)
            '__crWeb',
            '__gCrWeb',
            // Yandex Browser on iOS, macOS and Android (checked in 21.2 on iOS 14, macOS and Android)
            'yandex',
            // Yandex Browser on iOS (checked in 21.2 on 14)
            '__yb',
            '__ybro',
            // Firefox on iOS (checked in 32 on 14)
            '__firefox__',
            // Edge on iOS (checked in 46 on 14)
            '__edgeTrackingPreventionStatistics',
            'webkit',
            // Opera Touch on iOS (checked in 2.6 on 14)
            'oprt',
            // Samsung Internet on Android (checked in 11.1)
            'samsungAr',
            // UC Browser on Android (checked in 12.10 and 13.0)
            'ucweb',
            'UCShellJava',
            // Puffin on Android (checked in 9.0)
            'puffinDevice',
            // UC on iOS and Opera on Android have no specific global variables
            // Edge for Android isn't checked
        ]; _i < _a.length; _i++) {
            var key = _a[_i];
            var value = window[key];
            if (value && typeof value === 'object') {
                flavors.push(key);
            }
        }
        return flavors.sort();
    }

    /**
     * navigator.cookieEnabled cannot detect custom or nuanced cookie blocking configurations. For example, when blocking
     * cookies via the Advanced Privacy Settings in IE9, it always returns true. And there have been issues in the past with
     * site-specific exceptions. Don't rely on it.
     *
     * @see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cookies.js Taken from here
     */
    function areCookiesEnabled() {
        var d = document;
        // Taken from here: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cookies.js
        // navigator.cookieEnabled cannot detect custom or nuanced cookie blocking configurations. For example, when blocking
        // cookies via the Advanced Privacy Settings in IE9, it always returns true. And there have been issues in the past
        // with site-specific exceptions. Don't rely on it.
        // try..catch because some in situations `document.cookie` is exposed but throws a
        // SecurityError if you try to access it; e.g. documents created from data URIs
        // or in sandboxed iframes (depending on flags/context)
        try {
            // Create cookie
            d.cookie = 'cookietest=1; SameSite=Strict;';
            var result = d.cookie.indexOf('cookietest=') !== -1;
            // Delete cookie
            d.cookie = 'cookietest=1; SameSite=Strict; expires=Thu, 01-Jan-1970 00:00:01 GMT';
            return result;
        }
        catch (e) {
            return false;
        }
    }

    /**
     * Only single element selector are supported (no operators like space, +, >, etc).
     * `embed` and `position: fixed;` will be considered as blocked anyway because it always has no offsetParent.
     * Avoid `iframe` and anything with `[src=]` because they produce excess HTTP requests.
     *
     * The "inappropriate" selectors are obfuscated. See https://github.com/fingerprintjs/fingerprintjs/issues/734.
     * A function is used instead of a plain object to help tree-shaking.
     *
     * The function code is generated automatically. See docs/content_blockers.md to learn how to make the list.
     */
    function getFilters() {
        var fromB64 = atob; // Just for better minification
        return {
            abpIndo: [
                '#Iklan-Melayang',
                '#Kolom-Iklan-728',
                '#SidebarIklan-wrapper',
                '[title="ALIENBOLA" i]',
                fromB64('I0JveC1CYW5uZXItYWRz'),
            ],
            abpvn: ['.quangcao', '#mobileCatfish', fromB64('LmNsb3NlLWFkcw=='), '[id^="bn_bottom_fixed_"]', '#pmadv'],
            adBlockFinland: [
                '.mainostila',
                fromB64('LnNwb25zb3JpdA=='),
                '.ylamainos',
                fromB64('YVtocmVmKj0iL2NsaWNrdGhyZ2guYXNwPyJd'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9hcHAucmVhZHBlYWsuY29tL2FkcyJd'),
            ],
            adBlockPersian: [
                '#navbar_notice_50',
                '.kadr',
                'TABLE[width="140px"]',
                '#divAgahi',
                fromB64('YVtocmVmXj0iaHR0cDovL2cxLnYuZndtcm0ubmV0L2FkLyJd'),
            ],
            adBlockWarningRemoval: [
                '#adblock-honeypot',
                '.adblocker-root',
                '.wp_adblock_detect',
                fromB64('LmhlYWRlci1ibG9ja2VkLWFk'),
                fromB64('I2FkX2Jsb2NrZXI='),
            ],
            adGuardAnnoyances: [
                '.hs-sosyal',
                '#cookieconsentdiv',
                'div[class^="app_gdpr"]',
                '.as-oil',
                '[data-cypress="soft-push-notification-modal"]',
            ],
            adGuardBase: [
                '.BetterJsPopOverlay',
                fromB64('I2FkXzMwMFgyNTA='),
                fromB64('I2Jhbm5lcmZsb2F0MjI='),
                fromB64('I2NhbXBhaWduLWJhbm5lcg=='),
                fromB64('I0FkLUNvbnRlbnQ='),
            ],
            adGuardChinese: [
                fromB64('LlppX2FkX2FfSA=='),
                fromB64('YVtocmVmKj0iLmh0aGJldDM0LmNvbSJd'),
                '#widget-quan',
                fromB64('YVtocmVmKj0iLzg0OTkyMDIwLnh5eiJd'),
                fromB64('YVtocmVmKj0iLjE5NTZobC5jb20vIl0='),
            ],
            adGuardFrench: [
                '#pavePub',
                fromB64('LmFkLWRlc2t0b3AtcmVjdGFuZ2xl'),
                '.mobile_adhesion',
                '.widgetadv',
                fromB64('LmFkc19iYW4='),
            ],
            adGuardGerman: ['aside[data-portal-id="leaderboard"]'],
            adGuardJapanese: [
                '#kauli_yad_1',
                fromB64('YVtocmVmXj0iaHR0cDovL2FkMi50cmFmZmljZ2F0ZS5uZXQvIl0='),
                fromB64('Ll9wb3BJbl9pbmZpbml0ZV9hZA=='),
                fromB64('LmFkZ29vZ2xl'),
                fromB64('Ll9faXNib29zdFJldHVybkFk'),
            ],
            adGuardMobile: [
                fromB64('YW1wLWF1dG8tYWRz'),
                fromB64('LmFtcF9hZA=='),
                'amp-embed[type="24smi"]',
                '#mgid_iframe1',
                fromB64('I2FkX2ludmlld19hcmVh'),
            ],
            adGuardRussian: [
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9hZC5sZXRtZWFkcy5jb20vIl0='),
                fromB64('LnJlY2xhbWE='),
                'div[id^="smi2adblock"]',
                fromB64('ZGl2W2lkXj0iQWRGb3hfYmFubmVyXyJd'),
                '#psyduckpockeball',
            ],
            adGuardSocial: [
                fromB64('YVtocmVmXj0iLy93d3cuc3R1bWJsZXVwb24uY29tL3N1Ym1pdD91cmw9Il0='),
                fromB64('YVtocmVmXj0iLy90ZWxlZ3JhbS5tZS9zaGFyZS91cmw/Il0='),
                '.etsy-tweet',
                '#inlineShare',
                '.popup-social',
            ],
            adGuardSpanishPortuguese: ['#barraPublicidade', '#Publicidade', '#publiEspecial', '#queTooltip', '.cnt-publi'],
            adGuardTrackingProtection: [
                '#qoo-counter',
                fromB64('YVtocmVmXj0iaHR0cDovL2NsaWNrLmhvdGxvZy5ydS8iXQ=='),
                fromB64('YVtocmVmXj0iaHR0cDovL2hpdGNvdW50ZXIucnUvdG9wL3N0YXQucGhwIl0='),
                fromB64('YVtocmVmXj0iaHR0cDovL3RvcC5tYWlsLnJ1L2p1bXAiXQ=='),
                '#top100counter',
            ],
            adGuardTurkish: [
                '#backkapat',
                fromB64('I3Jla2xhbWk='),
                fromB64('YVtocmVmXj0iaHR0cDovL2Fkc2Vydi5vbnRlay5jb20udHIvIl0='),
                fromB64('YVtocmVmXj0iaHR0cDovL2l6bGVuemkuY29tL2NhbXBhaWduLyJd'),
                fromB64('YVtocmVmXj0iaHR0cDovL3d3dy5pbnN0YWxsYWRzLm5ldC8iXQ=='),
            ],
            bulgarian: [fromB64('dGQjZnJlZW5ldF90YWJsZV9hZHM='), '#ea_intext_div', '.lapni-pop-over', '#xenium_hot_offers'],
            easyList: [
                '.yb-floorad',
                fromB64('LndpZGdldF9wb19hZHNfd2lkZ2V0'),
                fromB64('LnRyYWZmaWNqdW5reS1hZA=='),
                '.textad_headline',
                fromB64('LnNwb25zb3JlZC10ZXh0LWxpbmtz'),
            ],
            easyListChina: [
                fromB64('LmFwcGd1aWRlLXdyYXBbb25jbGljayo9ImJjZWJvcy5jb20iXQ=='),
                fromB64('LmZyb250cGFnZUFkdk0='),
                '#taotaole',
                '#aafoot.top_box',
                '.cfa_popup',
            ],
            easyListCookie: [
                '.ezmob-footer',
                '.cc-CookieWarning',
                '[data-cookie-number]',
                fromB64('LmF3LWNvb2tpZS1iYW5uZXI='),
                '.sygnal24-gdpr-modal-wrap',
            ],
            easyListCzechSlovak: [
                '#onlajny-stickers',
                fromB64('I3Jla2xhbW5pLWJveA=='),
                fromB64('LnJla2xhbWEtbWVnYWJvYXJk'),
                '.sklik',
                fromB64('W2lkXj0ic2tsaWtSZWtsYW1hIl0='),
            ],
            easyListDutch: [
                fromB64('I2FkdmVydGVudGll'),
                fromB64('I3ZpcEFkbWFya3RCYW5uZXJCbG9jaw=='),
                '.adstekst',
                fromB64('YVtocmVmXj0iaHR0cHM6Ly94bHR1YmUubmwvY2xpY2svIl0='),
                '#semilo-lrectangle',
            ],
            easyListGermany: [
                '#SSpotIMPopSlider',
                fromB64('LnNwb25zb3JsaW5rZ3J1ZW4='),
                fromB64('I3dlcmJ1bmdza3k='),
                fromB64('I3Jla2xhbWUtcmVjaHRzLW1pdHRl'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9iZDc0Mi5jb20vIl0='),
            ],
            easyListItaly: [
                fromB64('LmJveF9hZHZfYW5udW5jaQ=='),
                '.sb-box-pubbliredazionale',
                fromB64('YVtocmVmXj0iaHR0cDovL2FmZmlsaWF6aW9uaWFkcy5zbmFpLml0LyJd'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9hZHNlcnZlci5odG1sLml0LyJd'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9hZmZpbGlhemlvbmlhZHMuc25haS5pdC8iXQ=='),
            ],
            easyListLithuania: [
                fromB64('LnJla2xhbW9zX3RhcnBhcw=='),
                fromB64('LnJla2xhbW9zX251b3JvZG9z'),
                fromB64('aW1nW2FsdD0iUmVrbGFtaW5pcyBza3lkZWxpcyJd'),
                fromB64('aW1nW2FsdD0iRGVkaWt1b3RpLmx0IHNlcnZlcmlhaSJd'),
                fromB64('aW1nW2FsdD0iSG9zdGluZ2FzIFNlcnZlcmlhaS5sdCJd'),
            ],
            estonian: [fromB64('QVtocmVmKj0iaHR0cDovL3BheTRyZXN1bHRzMjQuZXUiXQ==')],
            fanboyAnnoyances: ['#ac-lre-player', '.navigate-to-top', '#subscribe_popup', '.newsletter_holder', '#back-top'],
            fanboyAntiFacebook: ['.util-bar-module-firefly-visible'],
            fanboyEnhancedTrackers: [
                '.open.pushModal',
                '#issuem-leaky-paywall-articles-zero-remaining-nag',
                '#sovrn_container',
                'div[class$="-hide"][zoompage-fontsize][style="display: block;"]',
                '.BlockNag__Card',
            ],
            fanboySocial: ['#FollowUs', '#meteored_share', '#social_follow', '.article-sharer', '.community__social-desc'],
            frellwitSwedish: [
                fromB64('YVtocmVmKj0iY2FzaW5vcHJvLnNlIl1bdGFyZ2V0PSJfYmxhbmsiXQ=='),
                fromB64('YVtocmVmKj0iZG9rdG9yLXNlLm9uZWxpbmsubWUiXQ=='),
                'article.category-samarbete',
                fromB64('ZGl2LmhvbGlkQWRz'),
                'ul.adsmodern',
            ],
            greekAdBlock: [
                fromB64('QVtocmVmKj0iYWRtYW4ub3RlbmV0LmdyL2NsaWNrPyJd'),
                fromB64('QVtocmVmKj0iaHR0cDovL2F4aWFiYW5uZXJzLmV4b2R1cy5nci8iXQ=='),
                fromB64('QVtocmVmKj0iaHR0cDovL2ludGVyYWN0aXZlLmZvcnRobmV0LmdyL2NsaWNrPyJd'),
                'DIV.agores300',
                'TABLE.advright',
            ],
            hungarian: [
                '#cemp_doboz',
                '.optimonk-iframe-container',
                fromB64('LmFkX19tYWlu'),
                fromB64('W2NsYXNzKj0iR29vZ2xlQWRzIl0='),
                '#hirdetesek_box',
            ],
            iDontCareAboutCookies: [
                '.alert-info[data-block-track*="CookieNotice"]',
                '.ModuleTemplateCookieIndicator',
                '.o--cookies--container',
                '#cookies-policy-sticky',
                '#stickyCookieBar',
            ],
            icelandicAbp: [fromB64('QVtocmVmXj0iL2ZyYW1ld29yay9yZXNvdXJjZXMvZm9ybXMvYWRzLmFzcHgiXQ==')],
            latvian: [
                fromB64('YVtocmVmPSJodHRwOi8vd3d3LnNhbGlkemluaS5sdi8iXVtzdHlsZT0iZGlzcGxheTogYmxvY2s7IHdpZHRoOiAxMjBweDsgaGVpZ2h0O' +
                    'iA0MHB4OyBvdmVyZmxvdzogaGlkZGVuOyBwb3NpdGlvbjogcmVsYXRpdmU7Il0='),
                fromB64('YVtocmVmPSJodHRwOi8vd3d3LnNhbGlkemluaS5sdi8iXVtzdHlsZT0iZGlzcGxheTogYmxvY2s7IHdpZHRoOiA4OHB4OyBoZWlnaHQ6I' +
                    'DMxcHg7IG92ZXJmbG93OiBoaWRkZW47IHBvc2l0aW9uOiByZWxhdGl2ZTsiXQ=='),
            ],
            listKr: [
                fromB64('YVtocmVmKj0iLy9hZC5wbGFuYnBsdXMuY28ua3IvIl0='),
                fromB64('I2xpdmVyZUFkV3JhcHBlcg=='),
                fromB64('YVtocmVmKj0iLy9hZHYuaW1hZHJlcC5jby5rci8iXQ=='),
                fromB64('aW5zLmZhc3R2aWV3LWFk'),
                '.revenue_unit_item.dable',
            ],
            listeAr: [
                fromB64('LmdlbWluaUxCMUFk'),
                '.right-and-left-sponsers',
                fromB64('YVtocmVmKj0iLmFmbGFtLmluZm8iXQ=='),
                fromB64('YVtocmVmKj0iYm9vcmFxLm9yZyJd'),
                fromB64('YVtocmVmKj0iZHViaXp6bGUuY29tL2FyLz91dG1fc291cmNlPSJd'),
            ],
            listeFr: [
                fromB64('YVtocmVmXj0iaHR0cDovL3Byb21vLnZhZG9yLmNvbS8iXQ=='),
                fromB64('I2FkY29udGFpbmVyX3JlY2hlcmNoZQ=='),
                fromB64('YVtocmVmKj0id2Vib3JhbWEuZnIvZmNnaS1iaW4vIl0='),
                '.site-pub-interstitiel',
                'div[id^="crt-"][data-criteo-id]',
            ],
            officialPolish: [
                '#ceneo-placeholder-ceneo-12',
                fromB64('W2hyZWZePSJodHRwczovL2FmZi5zZW5kaHViLnBsLyJd'),
                fromB64('YVtocmVmXj0iaHR0cDovL2Fkdm1hbmFnZXIudGVjaGZ1bi5wbC9yZWRpcmVjdC8iXQ=='),
                fromB64('YVtocmVmXj0iaHR0cDovL3d3dy50cml6ZXIucGwvP3V0bV9zb3VyY2UiXQ=='),
                fromB64('ZGl2I3NrYXBpZWNfYWQ='),
            ],
            ro: [
                fromB64('YVtocmVmXj0iLy9hZmZ0cmsuYWx0ZXgucm8vQ291bnRlci9DbGljayJd'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9ibGFja2ZyaWRheXNhbGVzLnJvL3Ryay9zaG9wLyJd'),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9ldmVudC4ycGVyZm9ybWFudC5jb20vZXZlbnRzL2NsaWNrIl0='),
                fromB64('YVtocmVmXj0iaHR0cHM6Ly9sLnByb2ZpdHNoYXJlLnJvLyJd'),
                'a[href^="/url/"]',
            ],
            ruAd: [
                fromB64('YVtocmVmKj0iLy9mZWJyYXJlLnJ1LyJd'),
                fromB64('YVtocmVmKj0iLy91dGltZy5ydS8iXQ=='),
                fromB64('YVtocmVmKj0iOi8vY2hpa2lkaWtpLnJ1Il0='),
                '#pgeldiz',
                '.yandex-rtb-block',
            ],
            thaiAds: [
                'a[href*=macau-uta-popup]',
                fromB64('I2Fkcy1nb29nbGUtbWlkZGxlX3JlY3RhbmdsZS1ncm91cA=='),
                fromB64('LmFkczMwMHM='),
                '.bumq',
                '.img-kosana',
            ],
            webAnnoyancesUltralist: [
                '#mod-social-share-2',
                '#social-tools',
                fromB64('LmN0cGwtZnVsbGJhbm5lcg=='),
                '.zergnet-recommend',
                '.yt.btn-link.btn-md.btn',
            ],
        };
    }
    /**
     * The order of the returned array means nothing (it's always sorted alphabetically).
     *
     * Notice that the source is slightly unstable.
     * Safari provides a 2-taps way to disable all content blockers on a page temporarily.
     * Also content blockers can be disabled permanently for a domain, but it requires 4 taps.
     * So empty array shouldn't be treated as "no blockers", it should be treated as "no signal".
     * If you are a website owner, don't make your visitors want to disable content blockers.
     */
    function getDomBlockers(_a) {
        var _b = _a === void 0 ? {} : _a, debug = _b.debug;
        return __awaiter(this, void 0, void 0, function () {
            var filters, filterNames, allSelectors, blockedSelectors, activeBlockers;
            var _c;
            return __generator(this, function (_d) {
                switch (_d.label) {
                    case 0:
                        if (!isApplicable()) {
                            return [2 /*return*/, undefined];
                        }
                        filters = getFilters();
                        filterNames = Object.keys(filters);
                        allSelectors = (_c = []).concat.apply(_c, filterNames.map(function (filterName) { return filters[filterName]; }));
                        return [4 /*yield*/, getBlockedSelectors(allSelectors)];
                    case 1:
                        blockedSelectors = _d.sent();
                        if (debug) {
                            printDebug(filters, blockedSelectors);
                        }
                        activeBlockers = filterNames.filter(function (filterName) {
                            var selectors = filters[filterName];
                            var blockedCount = countTruthy(selectors.map(function (selector) { return blockedSelectors[selector]; }));
                            return blockedCount > selectors.length * 0.6;
                        });
                        activeBlockers.sort();
                        return [2 /*return*/, activeBlockers];
                }
            });
        });
    }
    function isApplicable() {
        // Safari (desktop and mobile) and all Android browsers keep content blockers in both regular and private mode
        return isWebKit() || isAndroid();
    }
    function getBlockedSelectors(selectors) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var d, root, elements, blockedSelectors, i, element, holder, i;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        d = document;
                        root = d.createElement('div');
                        elements = new Array(selectors.length);
                        blockedSelectors = {} // Set() isn't used just in case somebody need older browser support
                        ;
                        forceShow(root);
                        // First create all elements that can be blocked. If the DOM steps below are done in a single cycle,
                        // browser will alternate tree modification and layout reading, that is very slow.
                        for (i = 0; i < selectors.length; ++i) {
                            element = selectorToElement(selectors[i]);
                            if (element.tagName === 'DIALOG') {
                                element.show();
                            }
                            holder = d.createElement('div') // Protects from unwanted effects of `+` and `~` selectors of filters
                            ;
                            forceShow(holder);
                            holder.appendChild(element);
                            root.appendChild(holder);
                            elements[i] = element;
                        }
                        _b.label = 1;
                    case 1:
                        if (!!d.body) return [3 /*break*/, 3];
                        return [4 /*yield*/, wait(50)];
                    case 2:
                        _b.sent();
                        return [3 /*break*/, 1];
                    case 3:
                        d.body.appendChild(root);
                        try {
                            // Then check which of the elements are blocked
                            for (i = 0; i < selectors.length; ++i) {
                                if (!elements[i].offsetParent) {
                                    blockedSelectors[selectors[i]] = true;
                                }
                            }
                        }
                        finally {
                            // Then remove the elements
                            (_a = root.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(root);
                        }
                        return [2 /*return*/, blockedSelectors];
                }
            });
        });
    }
    function forceShow(element) {
        element.style.setProperty('visibility', 'hidden', 'important');
        element.style.setProperty('display', 'block', 'important');
    }
    function printDebug(filters, blockedSelectors) {
        var message = 'DOM blockers debug:\n```';
        for (var _i = 0, _a = Object.keys(filters); _i < _a.length; _i++) {
            var filterName = _a[_i];
            message += "\n".concat(filterName, ":");
            for (var _b = 0, _c = filters[filterName]; _b < _c.length; _b++) {
                var selector = _c[_b];
                message += "\n  ".concat(blockedSelectors[selector] ? '🚫' : '➡️', " ").concat(selector);
            }
        }
        // console.log is ok here because it's under a debug clause
        // eslint-disable-next-line no-console
        console.log("".concat(message, "\n```"));
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut
     */
    function getColorGamut() {
        // rec2020 includes p3 and p3 includes srgb
        for (var _i = 0, _a = ['rec2020', 'p3', 'srgb']; _i < _a.length; _i++) {
            var gamut = _a[_i];
            if (matchMedia("(color-gamut: ".concat(gamut, ")")).matches) {
                return gamut;
            }
        }
        return undefined;
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/inverted-colors
     */
    function areColorsInverted() {
        if (doesMatch$5('inverted')) {
            return true;
        }
        if (doesMatch$5('none')) {
            return false;
        }
        return undefined;
    }
    function doesMatch$5(value) {
        return matchMedia("(inverted-colors: ".concat(value, ")")).matches;
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/forced-colors
     */
    function areColorsForced() {
        if (doesMatch$4('active')) {
            return true;
        }
        if (doesMatch$4('none')) {
            return false;
        }
        return undefined;
    }
    function doesMatch$4(value) {
        return matchMedia("(forced-colors: ".concat(value, ")")).matches;
    }

    var maxValueToCheck = 100;
    /**
     * If the display is monochrome (e.g. black&white), the value will be ≥0 and will mean the number of bits per pixel.
     * If the display is not monochrome, the returned value will be 0.
     * If the browser doesn't support this feature, the returned value will be undefined.
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/monochrome
     */
    function getMonochromeDepth() {
        if (!matchMedia('(min-monochrome: 0)').matches) {
            // The media feature isn't supported by the browser
            return undefined;
        }
        // A variation of binary search algorithm can be used here.
        // But since expected values are very small (≤10), there is no sense in adding the complexity.
        for (var i = 0; i <= maxValueToCheck; ++i) {
            if (matchMedia("(max-monochrome: ".concat(i, ")")).matches) {
                return i;
            }
        }
        throw new Error('Too high value');
    }

    /**
     * @see https://www.w3.org/TR/mediaqueries-5/#prefers-contrast
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast
     */
    function getContrastPreference() {
        if (doesMatch$3('no-preference')) {
            return 0 /* ContrastPreference.None */;
        }
        // The sources contradict on the keywords. Probably 'high' and 'low' will never be implemented.
        // Need to check it when all browsers implement the feature.
        if (doesMatch$3('high') || doesMatch$3('more')) {
            return 1 /* ContrastPreference.More */;
        }
        if (doesMatch$3('low') || doesMatch$3('less')) {
            return -1 /* ContrastPreference.Less */;
        }
        if (doesMatch$3('forced')) {
            return 10 /* ContrastPreference.ForcedColors */;
        }
        return undefined;
    }
    function doesMatch$3(value) {
        return matchMedia("(prefers-contrast: ".concat(value, ")")).matches;
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
     */
    function isMotionReduced() {
        if (doesMatch$2('reduce')) {
            return true;
        }
        if (doesMatch$2('no-preference')) {
            return false;
        }
        return undefined;
    }
    function doesMatch$2(value) {
        return matchMedia("(prefers-reduced-motion: ".concat(value, ")")).matches;
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-transparency
     */
    function isTransparencyReduced() {
        if (doesMatch$1('reduce')) {
            return true;
        }
        if (doesMatch$1('no-preference')) {
            return false;
        }
        return undefined;
    }
    function doesMatch$1(value) {
        return matchMedia("(prefers-reduced-transparency: ".concat(value, ")")).matches;
    }

    /**
     * @see https://www.w3.org/TR/mediaqueries-5/#dynamic-range
     */
    function isHDR() {
        if (doesMatch('high')) {
            return true;
        }
        if (doesMatch('standard')) {
            return false;
        }
        return undefined;
    }
    function doesMatch(value) {
        return matchMedia("(dynamic-range: ".concat(value, ")")).matches;
    }

    var M = Math; // To reduce the minified code size
    var fallbackFn = function () { return 0; };
    /**
     * @see https://gitlab.torproject.org/legacy/trac/-/issues/13018
     * @see https://bugzilla.mozilla.org/show_bug.cgi?id=531915
     */
    function getMathFingerprint() {
        // Native operations
        var acos = M.acos || fallbackFn;
        var acosh = M.acosh || fallbackFn;
        var asin = M.asin || fallbackFn;
        var asinh = M.asinh || fallbackFn;
        var atanh = M.atanh || fallbackFn;
        var atan = M.atan || fallbackFn;
        var sin = M.sin || fallbackFn;
        var sinh = M.sinh || fallbackFn;
        var cos = M.cos || fallbackFn;
        var cosh = M.cosh || fallbackFn;
        var tan = M.tan || fallbackFn;
        var tanh = M.tanh || fallbackFn;
        var exp = M.exp || fallbackFn;
        var expm1 = M.expm1 || fallbackFn;
        var log1p = M.log1p || fallbackFn;
        // Operation polyfills
        var powPI = function (value) { return M.pow(M.PI, value); };
        var acoshPf = function (value) { return M.log(value + M.sqrt(value * value - 1)); };
        var asinhPf = function (value) { return M.log(value + M.sqrt(value * value + 1)); };
        var atanhPf = function (value) { return M.log((1 + value) / (1 - value)) / 2; };
        var sinhPf = function (value) { return M.exp(value) - 1 / M.exp(value) / 2; };
        var coshPf = function (value) { return (M.exp(value) + 1 / M.exp(value)) / 2; };
        var expm1Pf = function (value) { return M.exp(value) - 1; };
        var tanhPf = function (value) { return (M.exp(2 * value) - 1) / (M.exp(2 * value) + 1); };
        var log1pPf = function (value) { return M.log(1 + value); };
        // Note: constant values are empirical
        return {
            acos: acos(0.123124234234234242),
            acosh: acosh(1e308),
            acoshPf: acoshPf(1e154),
            asin: asin(0.123124234234234242),
            asinh: asinh(1),
            asinhPf: asinhPf(1),
            atanh: atanh(0.5),
            atanhPf: atanhPf(0.5),
            atan: atan(0.5),
            sin: sin(-1e300),
            sinh: sinh(1),
            sinhPf: sinhPf(1),
            cos: cos(10.000000000123),
            cosh: cosh(1),
            coshPf: coshPf(1),
            tan: tan(-1e300),
            tanh: tanh(1),
            tanhPf: tanhPf(1),
            exp: exp(1),
            expm1: expm1(1),
            expm1Pf: expm1Pf(1),
            log1p: log1p(10),
            log1pPf: log1pPf(10),
            powPI: powPI(-100),
        };
    }

    /**
     * We use m or w because these two characters take up the maximum width.
     * Also there are a couple of ligatures.
     */
    var defaultText = 'mmMwWLliI0fiflO&1';
    /**
     * Settings of text blocks to measure. The keys are random but persistent words.
     */
    var presets = {
        /**
         * The default font. User can change it in desktop Chrome, desktop Firefox, IE 11,
         * Android Chrome (but only when the size is ≥ than the default) and Android Firefox.
         */
        default: [],
        /** OS font on macOS. User can change its size and weight. Applies after Safari restart. */
        apple: [{ font: '-apple-system-body' }],
        /** User can change it in desktop Chrome and desktop Firefox. */
        serif: [{ fontFamily: 'serif' }],
        /** User can change it in desktop Chrome and desktop Firefox. */
        sans: [{ fontFamily: 'sans-serif' }],
        /** User can change it in desktop Chrome and desktop Firefox. */
        mono: [{ fontFamily: 'monospace' }],
        /**
         * Check the smallest allowed font size. User can change it in desktop Chrome, desktop Firefox and desktop Safari.
         * The height can be 0 in Chrome on a retina display.
         */
        min: [{ fontSize: '1px' }],
        /** Tells one OS from another in desktop Chrome. */
        system: [{ fontFamily: 'system-ui' }],
    };
    /**
     * The result is a dictionary of the width of the text samples.
     * Heights aren't included because they give no extra entropy and are unstable.
     *
     * The result is very stable in IE 11, Edge 18 and Safari 14.
     * The result changes when the OS pixel density changes in Chromium 87. The real pixel density is required to solve,
     * but seems like it's impossible: https://stackoverflow.com/q/1713771/1118709.
     * The "min" and the "mono" (only on Windows) value may change when the page is zoomed in Firefox 87.
     */
    function getFontPreferences() {
        return withNaturalFonts(function (document, container) {
            var elements = {};
            var sizes = {};
            // First create all elements to measure. If the DOM steps below are done in a single cycle,
            // browser will alternate tree modification and layout reading, that is very slow.
            for (var _i = 0, _a = Object.keys(presets); _i < _a.length; _i++) {
                var key = _a[_i];
                var _b = presets[key], _c = _b[0], style = _c === void 0 ? {} : _c, _d = _b[1], text = _d === void 0 ? defaultText : _d;
                var element = document.createElement('span');
                element.textContent = text;
                element.style.whiteSpace = 'nowrap';
                for (var _e = 0, _f = Object.keys(style); _e < _f.length; _e++) {
                    var name_1 = _f[_e];
                    var value = style[name_1];
                    if (value !== undefined) {
                        element.style[name_1] = value;
                    }
                }
                elements[key] = element;
                container.append(document.createElement('br'), element);
            }
            // Then measure the created elements
            for (var _g = 0, _h = Object.keys(presets); _g < _h.length; _g++) {
                var key = _h[_g];
                sizes[key] = elements[key].getBoundingClientRect().width;
            }
            return sizes;
        });
    }
    /**
     * Creates a DOM environment that provides the most natural font available, including Android OS font.
     * Measurements of the elements are zoom-independent.
     * Don't put a content to measure inside an absolutely positioned element.
     */
    function withNaturalFonts(action, containerWidthPx) {
        if (containerWidthPx === void 0) { containerWidthPx = 4000; }
        /*
         * Requirements for Android Chrome to apply the system font size to a text inside an iframe:
         * - The iframe mustn't have a `display: none;` style;
         * - The text mustn't be positioned absolutely;
         * - The text block must be wide enough.
         *   2560px on some devices in portrait orientation for the biggest font size option (32px);
         * - There must be much enough text to form a few lines (I don't know the exact numbers);
         * - The text must have the `text-size-adjust: none` style. Otherwise the text will scale in "Desktop site" mode;
         *
         * Requirements for Android Firefox to apply the system font size to a text inside an iframe:
         * - The iframe document must have a header: `<meta name="viewport" content="width=device-width, initial-scale=1" />`.
         *   The only way to set it is to use the `srcdoc` attribute of the iframe;
         * - The iframe content must get loaded before adding extra content with JavaScript;
         *
         * https://example.com as the iframe target always inherits Android font settings so it can be used as a reference.
         *
         * Observations on how page zoom affects the measurements:
         * - macOS Safari 11.1, 12.1, 13.1, 14.0: zoom reset + offsetWidth = 100% reliable;
         * - macOS Safari 11.1, 12.1, 13.1, 14.0: zoom reset + getBoundingClientRect = 100% reliable;
         * - macOS Safari 14.0: offsetWidth = 5% fluctuation;
         * - macOS Safari 14.0: getBoundingClientRect = 5% fluctuation;
         * - iOS Safari 9, 10, 11.0, 12.0: haven't found a way to zoom a page (pinch doesn't change layout);
         * - iOS Safari 13.1, 14.0: zoom reset + offsetWidth = 100% reliable;
         * - iOS Safari 13.1, 14.0: zoom reset + getBoundingClientRect = 100% reliable;
         * - iOS Safari 14.0: offsetWidth = 100% reliable;
         * - iOS Safari 14.0: getBoundingClientRect = 100% reliable;
         * - Chrome 42, 65, 80, 87: zoom 1/devicePixelRatio + offsetWidth = 1px fluctuation;
         * - Chrome 42, 65, 80, 87: zoom 1/devicePixelRatio + getBoundingClientRect = 100% reliable;
         * - Chrome 87: offsetWidth = 1px fluctuation;
         * - Chrome 87: getBoundingClientRect = 0.7px fluctuation;
         * - Firefox 48, 51: offsetWidth = 10% fluctuation;
         * - Firefox 48, 51: getBoundingClientRect = 10% fluctuation;
         * - Firefox 52, 53, 57, 62, 66, 67, 68, 71, 75, 80, 84: offsetWidth = width 100% reliable, height 10% fluctuation;
         * - Firefox 52, 53, 57, 62, 66, 67, 68, 71, 75, 80, 84: getBoundingClientRect = width 100% reliable, height 10%
         *   fluctuation;
         * - Android Chrome 86: haven't found a way to zoom a page (pinch doesn't change layout);
         * - Android Firefox 84: font size in accessibility settings changes all the CSS sizes, but offsetWidth and
         *   getBoundingClientRect keep measuring with regular units, so the size reflects the font size setting and doesn't
         *   fluctuate;
         * - IE 11, Edge 18: zoom 1/devicePixelRatio + offsetWidth = 100% reliable;
         * - IE 11, Edge 18: zoom 1/devicePixelRatio + getBoundingClientRect = reflects the zoom level;
         * - IE 11, Edge 18: offsetWidth = 100% reliable;
         * - IE 11, Edge 18: getBoundingClientRect = 100% reliable;
         */
        return withIframe(function (_, iframeWindow) {
            var iframeDocument = iframeWindow.document;
            var iframeBody = iframeDocument.body;
            var bodyStyle = iframeBody.style;
            bodyStyle.width = "".concat(containerWidthPx, "px");
            bodyStyle.webkitTextSizeAdjust = bodyStyle.textSizeAdjust = 'none';
            // See the big comment above
            if (isChromium()) {
                iframeBody.style.zoom = "".concat(1 / iframeWindow.devicePixelRatio);
            }
            else if (isWebKit()) {
                iframeBody.style.zoom = 'reset';
            }
            // See the big comment above
            var linesOfText = iframeDocument.createElement('div');
            linesOfText.textContent = __spreadArray([], Array((containerWidthPx / 20) << 0), true).map(function () { return 'word'; }).join(' ');
            iframeBody.appendChild(linesOfText);
            return action(iframeDocument, iframeBody);
        }, '<!doctype html><html><head><meta name="viewport" content="width=device-width, initial-scale=1">');
    }

    function isPdfViewerEnabled() {
        return navigator.pdfViewerEnabled;
    }

    /**
     * Unlike most other architectures, on x86/x86-64 when floating-point instructions
     * have no NaN arguments, but produce NaN output, the output NaN has sign bit set.
     * We use it to distinguish x86/x86-64 from other architectures, by doing subtraction
     * of two infinities (must produce NaN per IEEE 754 standard).
     *
     * See https://codebrowser.bddppq.com/pytorch/pytorch/third_party/XNNPACK/src/init.c.html#79
     */
    function getArchitecture() {
        var f = new Float32Array(1);
        var u8 = new Uint8Array(f.buffer);
        f[0] = Infinity;
        f[0] = f[0] - f[0];
        return u8[3];
    }

    /**
     * The return type is a union instead of the enum, because it's too challenging to embed the const enum into another
     * project. Turning it into a union is a simple and an elegant solution.
     */
    function getApplePayState() {
        var ApplePaySession = window.ApplePaySession;
        if (typeof (ApplePaySession === null || ApplePaySession === void 0 ? void 0 : ApplePaySession.canMakePayments) !== 'function') {
            return -1 /* ApplePayState.NoAPI */;
        }
        if (willPrintConsoleError()) {
            return -3 /* ApplePayState.NotAvailableInFrame */;
        }
        try {
            return ApplePaySession.canMakePayments() ? 1 /* ApplePayState.Enabled */ : 0 /* ApplePayState.Disabled */;
        }
        catch (error) {
            return getStateFromError(error);
        }
    }
    /**
     * Starting from Safari 15 calling `ApplePaySession.canMakePayments()` produces this error message when FingerprintJS
     * runs in an iframe with a cross-origin parent page, and the iframe on that page has no allow="payment *" attribute:
     *   Feature policy 'Payment' check failed for element with origin 'https://example.com' and allow attribute ''.
     * This function checks whether the error message is expected.
     *
     * We check for cross-origin parents, which is prone to false-positive results. Instead, we should check for allowed
     * feature/permission, but we can't because none of these API works in Safari yet:
     *   navigator.permissions.query({ name: ‘payment' })
     *   navigator.permissions.query({ name: ‘payment-handler' })
     *   document.featurePolicy
     */
    var willPrintConsoleError = isAnyParentCrossOrigin;
    function getStateFromError(error) {
        // See full expected error messages in the test
        if (error instanceof Error && error.name === 'InvalidAccessError' && /\bfrom\b.*\binsecure\b/i.test(error.message)) {
            return -2 /* ApplePayState.NotAvailableInInsecureContext */;
        }
        throw error;
    }

    /**
     * Checks whether the Safari's Privacy Preserving Ad Measurement setting is on.
     * The setting is on when the value is not undefined.
     * A.k.a. private click measurement, privacy-preserving ad attribution.
     *
     * Unfortunately, it doesn't work in mobile Safari.
     * Probably, it will start working in mobile Safari or stop working in desktop Safari later.
     * We've found no way to detect the setting state in mobile Safari. Help wanted.
     *
     * @see https://webkit.org/blog/11529/introducing-private-click-measurement-pcm/
     * @see https://developer.apple.com/videos/play/wwdc2021/10033
     */
    function getPrivateClickMeasurement() {
        var _a;
        var link = document.createElement('a');
        var sourceId = (_a = link.attributionSourceId) !== null && _a !== void 0 ? _a : link.attributionsourceid;
        return sourceId === undefined ? undefined : String(sourceId);
    }

    /** WebGl context is not available */
    var STATUS_NO_GL_CONTEXT = -1;
    /** WebGL context `getParameter` method is not a function */
    var STATUS_GET_PARAMETER_NOT_A_FUNCTION = -2;
    var validContextParameters = new Set([
        10752, 2849, 2884, 2885, 2886, 2928, 2929, 2930, 2931, 2932, 2960, 2961, 2962, 2963, 2964, 2965, 2966, 2967, 2968,
        2978, 3024, 3042, 3088, 3089, 3106, 3107, 32773, 32777, 32777, 32823, 32824, 32936, 32937, 32938, 32939, 32968, 32969,
        32970, 32971, 3317, 33170, 3333, 3379, 3386, 33901, 33902, 34016, 34024, 34076, 3408, 3410, 3411, 3412, 3413, 3414,
        3415, 34467, 34816, 34817, 34818, 34819, 34877, 34921, 34930, 35660, 35661, 35724, 35738, 35739, 36003, 36004, 36005,
        36347, 36348, 36349, 37440, 37441, 37443, 7936, 7937, 7938,
        // SAMPLE_ALPHA_TO_COVERAGE (32926) and SAMPLE_COVERAGE (32928) are excluded because they trigger a console warning
        // in IE, Chrome ≤ 59 and Safari ≤ 13 and give no entropy.
    ]);
    var validExtensionParams = new Set([
        34047,
        35723,
        36063,
        34852,
        34853,
        34854,
        34229,
        36392,
        36795,
        38449, // MAX_VIEWS_OVR
    ]);
    var shaderTypes = ['FRAGMENT_SHADER', 'VERTEX_SHADER'];
    var precisionTypes = ['LOW_FLOAT', 'MEDIUM_FLOAT', 'HIGH_FLOAT', 'LOW_INT', 'MEDIUM_INT', 'HIGH_INT'];
    var rendererInfoExtensionName = 'WEBGL_debug_renderer_info';
    var polygonModeExtensionName = 'WEBGL_polygon_mode';
    /**
     * Gets the basic and simple WebGL parameters
     */
    function getWebGlBasics(_a) {
        var _b, _c, _d, _e, _f, _g;
        var cache = _a.cache;
        var gl = getWebGLContext(cache);
        if (!gl) {
            return STATUS_NO_GL_CONTEXT;
        }
        if (!isValidParameterGetter(gl)) {
            return STATUS_GET_PARAMETER_NOT_A_FUNCTION;
        }
        var debugExtension = shouldAvoidDebugRendererInfo() ? null : gl.getExtension(rendererInfoExtensionName);
        return {
            version: ((_b = gl.getParameter(gl.VERSION)) === null || _b === void 0 ? void 0 : _b.toString()) || '',
            vendor: ((_c = gl.getParameter(gl.VENDOR)) === null || _c === void 0 ? void 0 : _c.toString()) || '',
            vendorUnmasked: debugExtension ? (_d = gl.getParameter(debugExtension.UNMASKED_VENDOR_WEBGL)) === null || _d === void 0 ? void 0 : _d.toString() : '',
            renderer: ((_e = gl.getParameter(gl.RENDERER)) === null || _e === void 0 ? void 0 : _e.toString()) || '',
            rendererUnmasked: debugExtension ? (_f = gl.getParameter(debugExtension.UNMASKED_RENDERER_WEBGL)) === null || _f === void 0 ? void 0 : _f.toString() : '',
            shadingLanguageVersion: ((_g = gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) === null || _g === void 0 ? void 0 : _g.toString()) || '',
        };
    }
    /**
     * Gets the advanced and massive WebGL parameters and extensions
     */
    function getWebGlExtensions(_a) {
        var cache = _a.cache;
        var gl = getWebGLContext(cache);
        if (!gl) {
            return STATUS_NO_GL_CONTEXT;
        }
        if (!isValidParameterGetter(gl)) {
            return STATUS_GET_PARAMETER_NOT_A_FUNCTION;
        }
        var extensions = gl.getSupportedExtensions();
        var contextAttributes = gl.getContextAttributes();
        var unsupportedExtensions = [];
        // Features
        var attributes = [];
        var parameters = [];
        var extensionParameters = [];
        var shaderPrecisions = [];
        // Context attributes
        if (contextAttributes) {
            for (var _i = 0, _b = Object.keys(contextAttributes); _i < _b.length; _i++) {
                var attributeName = _b[_i];
                attributes.push("".concat(attributeName, "=").concat(contextAttributes[attributeName]));
            }
        }
        // Context parameters
        var constants = getConstantsFromPrototype(gl);
        for (var _c = 0, constants_1 = constants; _c < constants_1.length; _c++) {
            var constant = constants_1[_c];
            var code = gl[constant];
            parameters.push("".concat(constant, "=").concat(code).concat(validContextParameters.has(code) ? "=".concat(gl.getParameter(code)) : ''));
        }
        // Extension parameters
        if (extensions) {
            for (var _d = 0, extensions_1 = extensions; _d < extensions_1.length; _d++) {
                var name_1 = extensions_1[_d];
                if ((name_1 === rendererInfoExtensionName && shouldAvoidDebugRendererInfo()) ||
                    (name_1 === polygonModeExtensionName && shouldAvoidPolygonModeExtensions())) {
                    continue;
                }
                var extension = gl.getExtension(name_1);
                if (!extension) {
                    unsupportedExtensions.push(name_1);
                    continue;
                }
                for (var _e = 0, _f = getConstantsFromPrototype(extension); _e < _f.length; _e++) {
                    var constant = _f[_e];
                    var code = extension[constant];
                    extensionParameters.push("".concat(constant, "=").concat(code).concat(validExtensionParams.has(code) ? "=".concat(gl.getParameter(code)) : ''));
                }
            }
        }
        // Shader precision
        for (var _g = 0, shaderTypes_1 = shaderTypes; _g < shaderTypes_1.length; _g++) {
            var shaderType = shaderTypes_1[_g];
            for (var _h = 0, precisionTypes_1 = precisionTypes; _h < precisionTypes_1.length; _h++) {
                var precisionType = precisionTypes_1[_h];
                var shaderPrecision = getShaderPrecision(gl, shaderType, precisionType);
                shaderPrecisions.push("".concat(shaderType, ".").concat(precisionType, "=").concat(shaderPrecision.join(',')));
            }
        }
        // Postprocess
        extensionParameters.sort();
        parameters.sort();
        return {
            contextAttributes: attributes,
            parameters: parameters,
            shaderPrecisions: shaderPrecisions,
            extensions: extensions,
            extensionParameters: extensionParameters,
            unsupportedExtensions: unsupportedExtensions,
        };
    }
    /**
     * This function usually takes the most time to execute in all the sources, therefore we cache its result.
     *
     * Warning for package users:
     * This function is out of Semantic Versioning, i.e. can change unexpectedly. Usage is at your own risk.
     */
    function getWebGLContext(cache) {
        if (cache.webgl) {
            return cache.webgl.context;
        }
        var canvas = document.createElement('canvas');
        var context;
        canvas.addEventListener('webglCreateContextError', function () { return (context = undefined); });
        for (var _i = 0, _a = ['webgl', 'experimental-webgl']; _i < _a.length; _i++) {
            var type = _a[_i];
            try {
                context = canvas.getContext(type);
            }
            catch (_b) {
                // Ok, continue
            }
            if (context) {
                break;
            }
        }
        cache.webgl = { context: context };
        return context;
    }
    /**
     * https://developer.mozilla.org/en-US/docs/Web/API/WebGLShaderPrecisionFormat
     * https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getShaderPrecisionFormat
     * https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.12
     */
    function getShaderPrecision(gl, shaderType, precisionType) {
        var shaderPrecision = gl.getShaderPrecisionFormat(gl[shaderType], gl[precisionType]);
        return shaderPrecision ? [shaderPrecision.rangeMin, shaderPrecision.rangeMax, shaderPrecision.precision] : [];
    }
    function getConstantsFromPrototype(obj) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        var keys = Object.keys(obj.__proto__);
        return keys.filter(isConstantLike);
    }
    function isConstantLike(key) {
        return typeof key === 'string' && !key.match(/[^A-Z0-9_x]/);
    }
    /**
     * Some browsers print a console warning when the WEBGL_debug_renderer_info extension is requested.
     * JS Agent aims to avoid printing messages to console, so we avoid this extension in that browsers.
     */
    function shouldAvoidDebugRendererInfo() {
        return isGecko();
    }
    /**
     * Some browsers print a console warning when the WEBGL_polygon_mode extension is requested.
     * JS Agent aims to avoid printing messages to console, so we avoid this extension in that browsers.
     */
    function shouldAvoidPolygonModeExtensions() {
        return isChromium() || isWebKit();
    }
    /**
     * Some unknown browsers have no `getParameter` method
     */
    function isValidParameterGetter(gl) {
        return typeof gl.getParameter === 'function';
    }

    function getAudioContextBaseLatency() {
        var _a;
        // The signal emits warning in Chrome and Firefox, therefore it is enabled on Safari where it doesn't produce warning
        // and on Android where it's less visible
        var isAllowedPlatform = isAndroid() || isWebKit();
        if (!isAllowedPlatform) {
            return -2 /* SpecialFingerprint.Disabled */;
        }
        if (!window.AudioContext) {
            return -1 /* SpecialFingerprint.NotSupported */;
        }
        return (_a = new AudioContext().baseLatency) !== null && _a !== void 0 ? _a : -1 /* SpecialFingerprint.NotSupported */;
    }

    /**
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions
     *
     * The return type is a union instead of a const enum due to the difficulty of embedding const enums in other projects.
     * This makes integration simpler and more elegant.
     */
    function getDateTimeLocale() {
        if (!window.Intl) {
            return -1 /* Status.IntlAPINotSupported */;
        }
        var DateTimeFormat = window.Intl.DateTimeFormat;
        if (!DateTimeFormat) {
            return -2 /* Status.DateTimeFormatNotSupported */;
        }
        var locale = DateTimeFormat().resolvedOptions().locale;
        if (!locale && locale !== '') {
            return -3 /* Status.LocaleNotAvailable */;
        }
        return locale;
    }

    /**
     * The list of entropy sources used to make visitor identifiers.
     *
     * This value isn't restricted by Semantic Versioning, i.e. it may be changed without bumping minor or major version of
     * this package.
     *
     * Note: Rollup and Webpack are smart enough to remove unused properties of this object during tree-shaking, so there is
     * no need to export the sources individually.
     */
    var sources = {
        // READ FIRST:
        // See https://github.com/fingerprintjs/fingerprintjs/blob/master/contributing.md#how-to-add-an-entropy-source
        // to learn how entropy source works and how to make your own.
        // The sources run in this exact order.
        // The asynchronous sources are at the start to run in parallel with other sources.
        fonts: getFonts,
        domBlockers: getDomBlockers,
        fontPreferences: getFontPreferences,
        audio: getAudioFingerprint,
        screenFrame: getScreenFrame,
        canvas: getCanvasFingerprint,
        osCpu: getOsCpu,
        languages: getLanguages,
        colorDepth: getColorDepth,
        deviceMemory: getDeviceMemory,
        screenResolution: getScreenResolution,
        hardwareConcurrency: getHardwareConcurrency,
        timezone: getTimezone,
        sessionStorage: getSessionStorage,
        localStorage: getLocalStorage,
        indexedDB: getIndexedDB,
        openDatabase: getOpenDatabase,
        cpuClass: getCpuClass,
        platform: getPlatform,
        plugins: getPlugins,
        touchSupport: getTouchSupport,
        vendor: getVendor,
        vendorFlavors: getVendorFlavors,
        cookiesEnabled: areCookiesEnabled,
        colorGamut: getColorGamut,
        invertedColors: areColorsInverted,
        forcedColors: areColorsForced,
        monochrome: getMonochromeDepth,
        contrast: getContrastPreference,
        reducedMotion: isMotionReduced,
        reducedTransparency: isTransparencyReduced,
        hdr: isHDR,
        math: getMathFingerprint,
        pdfViewerEnabled: isPdfViewerEnabled,
        architecture: getArchitecture,
        applePay: getApplePayState,
        privateClickMeasurement: getPrivateClickMeasurement,
        audioBaseLatency: getAudioContextBaseLatency,
        dateTimeLocale: getDateTimeLocale,
        // Some sources can affect other sources (e.g. WebGL can affect canvas), so it's important to run these sources
        // after other sources.
        webGlBasics: getWebGlBasics,
        webGlExtensions: getWebGlExtensions,
    };
    /**
     * Loads the built-in entropy sources.
     * Returns a function that collects the entropy components to make the visitor identifier.
     */
    function loadBuiltinSources(options) {
        return loadSources(sources, options, []);
    }

    var commentTemplate = '$ if upgrade to Pro: https://fpjs.dev/pro';
    function getConfidence(components) {
        var openConfidenceScore = getOpenConfidenceScore(components);
        var proConfidenceScore = deriveProConfidenceScore(openConfidenceScore);
        return { score: openConfidenceScore, comment: commentTemplate.replace(/\$/g, "".concat(proConfidenceScore)) };
    }
    function getOpenConfidenceScore(components) {
        // In order to calculate the true probability of the visitor identifier being correct, we need to know the number of
        // website visitors (the higher the number, the less the probability because the fingerprint entropy is limited).
        // JS agent doesn't know the number of visitors, so we can only do an approximate assessment.
        if (isAndroid()) {
            return 0.4;
        }
        // Safari (mobile and desktop)
        if (isWebKit()) {
            return isDesktopWebKit() && !(isWebKit616OrNewer() && isSafariWebKit()) ? 0.5 : 0.3;
        }
        var platform = 'value' in components.platform ? components.platform.value : '';
        // Windows
        if (/^Win/.test(platform)) {
            // The score is greater than on macOS because of the higher variety of devices running Windows.
            // Chrome provides more entropy than Firefox according too
            // https://netmarketshare.com/browser-market-share.aspx?options=%7B%22filter%22%3A%7B%22%24and%22%3A%5B%7B%22platform%22%3A%7B%22%24in%22%3A%5B%22Windows%22%5D%7D%7D%5D%7D%2C%22dateLabel%22%3A%22Trend%22%2C%22attributes%22%3A%22share%22%2C%22group%22%3A%22browser%22%2C%22sort%22%3A%7B%22share%22%3A-1%7D%2C%22id%22%3A%22browsersDesktop%22%2C%22dateInterval%22%3A%22Monthly%22%2C%22dateStart%22%3A%222019-11%22%2C%22dateEnd%22%3A%222020-10%22%2C%22segments%22%3A%22-1000%22%7D
            // So we assign the same score to them.
            return 0.6;
        }
        // macOS
        if (/^Mac/.test(platform)) {
            // Chrome provides more entropy than Safari and Safari provides more entropy than Firefox.
            // Chrome is more popular than Safari and Safari is more popular than Firefox according to
            // https://netmarketshare.com/browser-market-share.aspx?options=%7B%22filter%22%3A%7B%22%24and%22%3A%5B%7B%22platform%22%3A%7B%22%24in%22%3A%5B%22Mac%20OS%22%5D%7D%7D%5D%7D%2C%22dateLabel%22%3A%22Trend%22%2C%22attributes%22%3A%22share%22%2C%22group%22%3A%22browser%22%2C%22sort%22%3A%7B%22share%22%3A-1%7D%2C%22id%22%3A%22browsersDesktop%22%2C%22dateInterval%22%3A%22Monthly%22%2C%22dateStart%22%3A%222019-11%22%2C%22dateEnd%22%3A%222020-10%22%2C%22segments%22%3A%22-1000%22%7D
            // So we assign the same score to them.
            return 0.5;
        }
        // Another platform, e.g. a desktop Linux. It's rare, so it should be pretty unique.
        return 0.7;
    }
    function deriveProConfidenceScore(openConfidenceScore) {
        return round(0.99 + 0.01 * openConfidenceScore, 0.0001);
    }

    function componentsToCanonicalString(components) {
        var result = '';
        for (var _i = 0, _a = Object.keys(components).sort(); _i < _a.length; _i++) {
            var componentKey = _a[_i];
            var component = components[componentKey];
            var value = 'error' in component ? 'error' : JSON.stringify(component.value);
            result += "".concat(result ? '|' : '').concat(componentKey.replace(/([:|\\])/g, '\\$1'), ":").concat(value);
        }
        return result;
    }
    function componentsToDebugString(components) {
        return JSON.stringify(components, function (_key, value) {
            if (value instanceof Error) {
                return errorToObject(value);
            }
            return value;
        }, 2);
    }
    function hashComponents(components) {
        return x64hash128(componentsToCanonicalString(components));
    }
    /**
     * Makes a GetResult implementation that calculates the visitor id hash on demand.
     * Designed for optimisation.
     */
    function makeLazyGetResult(components) {
        var visitorIdCache;
        // This function runs very fast, so there is no need to make it lazy
        var confidence = getConfidence(components);
        // A plain class isn't used because its getters and setters aren't enumerable.
        return {
            get visitorId() {
                if (visitorIdCache === undefined) {
                    visitorIdCache = hashComponents(this.components);
                }
                return visitorIdCache;
            },
            set visitorId(visitorId) {
                visitorIdCache = visitorId;
            },
            confidence: confidence,
            components: components,
            version: version,
        };
    }
    /**
     * A delay is required to ensure consistent entropy components.
     * See https://github.com/fingerprintjs/fingerprintjs/issues/254
     * and https://github.com/fingerprintjs/fingerprintjs/issues/307
     * and https://github.com/fingerprintjs/fingerprintjs/commit/945633e7c5f67ae38eb0fea37349712f0e669b18
     */
    function prepareForSources(delayFallback) {
        if (delayFallback === void 0) { delayFallback = 50; }
        // A proper deadline is unknown. Let it be twice the fallback timeout so that both cases have the same average time.
        return requestIdleCallbackIfAvailable(delayFallback, delayFallback * 2);
    }
    /**
     * The function isn't exported from the index file to not allow to call it without `load()`.
     * The hiding gives more freedom for future non-breaking updates.
     *
     * A factory function is used instead of a class to shorten the attribute names in the minified code.
     * Native private class fields could've been used, but TypeScript doesn't allow them with `"target": "es5"`.
     */
    function makeAgent(getComponents, debug) {
        var creationTime = Date.now();
        return {
            get: function (options) {
                return __awaiter(this, void 0, void 0, function () {
                    var startTime, components, result;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                startTime = Date.now();
                                return [4 /*yield*/, getComponents()];
                            case 1:
                                components = _a.sent();
                                result = makeLazyGetResult(components);
                                if (debug || (options === null || options === void 0 ? void 0 : options.debug)) {
                                    // console.log is ok here because it's under a debug clause
                                    // eslint-disable-next-line no-console
                                    console.log("Copy the text below to get the debug data:\n\n```\nversion: ".concat(result.version, "\nuserAgent: ").concat(navigator.userAgent, "\ntimeBetweenLoadAndGet: ").concat(startTime - creationTime, "\nvisitorId: ").concat(result.visitorId, "\ncomponents: ").concat(componentsToDebugString(components), "\n```"));
                                }
                                return [2 /*return*/, result];
                        }
                    });
                });
            },
        };
    }
    /**
     * Sends an unpersonalized AJAX request to collect installation statistics
     */
    function monitor() {
        // The FingerprintJS CDN (https://github.com/fingerprintjs/cdn) replaces `window.__fpjs_d_m` with `true`
        if (window.__fpjs_d_m || Math.random() >= 0.001) {
            return;
        }
        try {
            var request = new XMLHttpRequest();
            request.open('get', "https://m1.openfpcdn.io/fingerprintjs/v".concat(version, "/npm-monitoring"), true);
            request.send();
        }
        catch (error) {
            // console.error is ok here because it's an unexpected error handler
            // eslint-disable-next-line no-console
            console.error(error);
        }
    }
    /**
     * Builds an instance of Agent and waits a delay required for a proper operation.
     */
    function load(options) {
        var _a;
        if (options === void 0) { options = {}; }
        return __awaiter(this, void 0, void 0, function () {
            var delayFallback, debug, getComponents;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        if ((_a = options.monitoring) !== null && _a !== void 0 ? _a : true) {
                            monitor();
                        }
                        delayFallback = options.delayFallback, debug = options.debug;
                        return [4 /*yield*/, prepareForSources(delayFallback)];
                    case 1:
                        _b.sent();
                        getComponents = loadBuiltinSources({ cache: {}, debug: debug });
                        return [2 /*return*/, makeAgent(getComponents, debug)];
                }
            });
        });
    }

    // The default export is a syntax sugar (`import * as FP from '...' → import FP from '...'`).
    // It should contain all the public exported values.
    var index = { load: load, hashComponents: hashComponents, componentsToDebugString: componentsToDebugString };
    // The exports below are for private usage. They may change unexpectedly. Use them at your own risk.
    /** Not documented, out of Semantic Versioning, usage is at your own risk */
    var murmurX64Hash128 = x64hash128;

    exports.componentsToDebugString = componentsToDebugString;
    exports.default = index;
    exports.getFullscreenElement = getFullscreenElement;
    exports.getUnstableAudioFingerprint = getUnstableAudioFingerprint;
    exports.getUnstableCanvasFingerprint = getUnstableCanvasFingerprint;
    exports.getUnstableScreenFrame = getUnstableScreenFrame;
    exports.getUnstableScreenResolution = getUnstableScreenResolution;
    exports.getWebGLContext = getWebGLContext;
    exports.hashComponents = hashComponents;
    exports.isAndroid = isAndroid;
    exports.isChromium = isChromium;
    exports.isDesktopWebKit = isDesktopWebKit;
    exports.isEdgeHTML = isEdgeHTML;
    exports.isGecko = isGecko;
    exports.isSamsungInternet = isSamsungInternet;
    exports.isTrident = isTrident;
    exports.isWebKit = isWebKit;
    exports.load = load;
    exports.loadSources = loadSources;
    exports.murmurX64Hash128 = murmurX64Hash128;
    exports.prepareForSources = prepareForSources;
    exports.sources = sources;
    exports.transformSource = transformSource;
    exports.withIframe = withIframe;

    Object.defineProperty(exports, '__esModule', { value: true });

}));

},{}],178:[function(require,module,exports){
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).libphonenumber={})}(this,(function(t){"use strict";var e={version:4,country_calling_codes:{1:["US","AG","AI","AS","BB","BM","BS","CA","DM","DO","GD","GU","JM","KN","KY","LC","MP","MS","PR","SX","TC","TT","VC","VG","VI"],7:["RU","KZ"],20:["EG"],27:["ZA"],30:["GR"],31:["NL"],32:["BE"],33:["FR"],34:["ES"],36:["HU"],39:["IT","VA"],40:["RO"],41:["CH"],43:["AT"],44:["GB","GG","IM","JE"],45:["DK"],46:["SE"],47:["NO","SJ"],48:["PL"],49:["DE"],51:["PE"],52:["MX"],53:["CU"],54:["AR"],55:["BR"],56:["CL"],57:["CO"],58:["VE"],60:["MY"],61:["AU","CC","CX"],62:["ID"],63:["PH"],64:["NZ"],65:["SG"],66:["TH"],81:["JP"],82:["KR"],84:["VN"],86:["CN"],90:["TR"],91:["IN"],92:["PK"],93:["AF"],94:["LK"],95:["MM"],98:["IR"],211:["SS"],212:["MA","EH"],213:["DZ"],216:["TN"],218:["LY"],220:["GM"],221:["SN"],222:["MR"],223:["ML"],224:["GN"],225:["CI"],226:["BF"],227:["NE"],228:["TG"],229:["BJ"],230:["MU"],231:["LR"],232:["SL"],233:["GH"],234:["NG"],235:["TD"],236:["CF"],237:["CM"],238:["CV"],239:["ST"],240:["GQ"],241:["GA"],242:["CG"],243:["CD"],244:["AO"],245:["GW"],246:["IO"],247:["AC"],248:["SC"],249:["SD"],250:["RW"],251:["ET"],252:["SO"],253:["DJ"],254:["KE"],255:["TZ"],256:["UG"],257:["BI"],258:["MZ"],260:["ZM"],261:["MG"],262:["RE","YT"],263:["ZW"],264:["NA"],265:["MW"],266:["LS"],267:["BW"],268:["SZ"],269:["KM"],290:["SH","TA"],291:["ER"],297:["AW"],298:["FO"],299:["GL"],350:["GI"],351:["PT"],352:["LU"],353:["IE"],354:["IS"],355:["AL"],356:["MT"],357:["CY"],358:["FI","AX"],359:["BG"],370:["LT"],371:["LV"],372:["EE"],373:["MD"],374:["AM"],375:["BY"],376:["AD"],377:["MC"],378:["SM"],380:["UA"],381:["RS"],382:["ME"],383:["XK"],385:["HR"],386:["SI"],387:["BA"],389:["MK"],420:["CZ"],421:["SK"],423:["LI"],500:["FK"],501:["BZ"],502:["GT"],503:["SV"],504:["HN"],505:["NI"],506:["CR"],507:["PA"],508:["PM"],509:["HT"],590:["GP","BL","MF"],591:["BO"],592:["GY"],593:["EC"],594:["GF"],595:["PY"],596:["MQ"],597:["SR"],598:["UY"],599:["CW","BQ"],670:["TL"],672:["NF"],673:["BN"],674:["NR"],675:["PG"],676:["TO"],677:["SB"],678:["VU"],679:["FJ"],680:["PW"],681:["WF"],682:["CK"],683:["NU"],685:["WS"],686:["KI"],687:["NC"],688:["TV"],689:["PF"],690:["TK"],691:["FM"],692:["MH"],850:["KP"],852:["HK"],853:["MO"],855:["KH"],856:["LA"],880:["BD"],886:["TW"],960:["MV"],961:["LB"],962:["JO"],963:["SY"],964:["IQ"],965:["KW"],966:["SA"],967:["YE"],968:["OM"],970:["PS"],971:["AE"],972:["IL"],973:["BH"],974:["QA"],975:["BT"],976:["MN"],977:["NP"],992:["TJ"],993:["TM"],994:["AZ"],995:["GE"],996:["KG"],998:["UZ"]},countries:{AC:["247","00","(?:[01589]\\d|[46])\\d{4}",[5,6],0,0,0,0,0,0,0,[0,["4\\d{4}",[5]]]],AD:["376","00","(?:1|6\\d)\\d{7}|[135-9]\\d{5}",[6,8,9],[["(\\d{3})(\\d{3})","$1 $2",["[135-9]"]],["(\\d{4})(\\d{4})","$1 $2",["1"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["6"]]],0,0,0,0,0,0,[0,["690\\d{6}|[356]\\d{5}",[6,9]]]],AE:["971","00","(?:[4-7]\\d|9[0-689])\\d{7}|800\\d{2,9}|[2-4679]\\d{7}",[5,6,7,8,9,10,11,12],[["(\\d{3})(\\d{2,9})","$1 $2",["60|8"]],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["[236]|[479][2-8]"],"0$1"],["(\\d{3})(\\d)(\\d{5})","$1 $2 $3",["[479]"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["5"],"0$1"]],"0",0,0,0,0,0,[0,["5[024-68]\\d{7}",[9]]]],AF:["93","00","[2-7]\\d{8}",[9],[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[2-7]"],"0$1"]],"0",0,0,0,0,0,[0,["7\\d{8}"]]],AG:["1","011","(?:268|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([457]\\d{6})$|1","268$1",0,"268",[0,["268(?:464|7(?:1[3-9]|[28]\\d|3[0246]|64|7[0-689]))\\d{4}"]]],AI:["1","011","(?:264|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2457]\\d{6})$|1","264$1",0,"264",[0,["264(?:235|4(?:69|76)|5(?:3[6-9]|8[1-4])|7(?:29|72))\\d{4}"]]],AL:["355","00","(?:700\\d\\d|900)\\d{3}|8\\d{5,7}|(?:[2-5]|6\\d)\\d{7}",[6,7,8,9],[["(\\d{3})(\\d{3,4})","$1 $2",["80|9"],"0$1"],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["4[2-6]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[2358][2-5]|4"],"0$1"],["(\\d{3})(\\d{5})","$1 $2",["[23578]"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["6"],"0$1"]],"0",0,0,0,0,0,[0,["6(?:[78][2-9]|9\\d)\\d{6}",[9]]]],AM:["374","00","(?:[1-489]\\d|55|60|77)\\d{6}",[8],[["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["[89]0"],"0 $1"],["(\\d{3})(\\d{5})","$1 $2",["2|3[12]"],"(0$1)"],["(\\d{2})(\\d{6})","$1 $2",["1|47"],"(0$1)"],["(\\d{2})(\\d{6})","$1 $2",["[3-9]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:33|4[1349]|55|77|88|9[13-9])\\d{6}"]]],AO:["244","00","[29]\\d{8}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[29]"]]],0,0,0,0,0,0,[0,["9[1-79]\\d{7}"]]],AR:["54","00","(?:11|[89]\\d\\d)\\d{8}|[2368]\\d{9}",[10,11],[["(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3",["2(?:2[024-9]|3[0-59]|47|6[245]|9[02-8])|3(?:3[28]|4[03-9]|5[2-46-8]|7[1-578]|8[2-9])","2(?:[23]02|6(?:[25]|4[6-8])|9(?:[02356]|4[02568]|72|8[23]))|3(?:3[28]|4(?:[04679]|3[5-8]|5[4-68]|8[2379])|5(?:[2467]|3[237]|8[2-5])|7[1-578]|8(?:[2469]|3[2578]|5[4-8]|7[36-8]|8[5-8]))|2(?:2[24-9]|3[1-59]|47)","2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3[78]|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8[23])|7[1-578]|8(?:[2469]|3[278]|5[56][46]|86[3-6]))|2(?:2[24-9]|3[1-59]|47)|38(?:[58][78]|7[378])|3(?:4[35][56]|58[45]|8(?:[38]5|54|76))[4-6]","2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3(?:5(?:4[0-25689]|[56])|[78])|58|8[2379])|5(?:[2467]|3[237]|8(?:[23]|4(?:[45]|60)|5(?:4[0-39]|5|64)))|7[1-578]|8(?:[2469]|3[278]|54(?:4|5[13-7]|6[89])|86[3-6]))|2(?:2[24-9]|3[1-59]|47)|38(?:[58][78]|7[378])|3(?:454|85[56])[46]|3(?:4(?:36|5[56])|8(?:[38]5|76))[4-6]"],"0$1",1],["(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3",["1"],"0$1",1],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["[68]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2-$3",["[23]"],"0$1",1],["(\\d)(\\d{4})(\\d{2})(\\d{4})","$2 15-$3-$4",["9(?:2[2-469]|3[3-578])","9(?:2(?:2[024-9]|3[0-59]|47|6[245]|9[02-8])|3(?:3[28]|4[03-9]|5[2-46-8]|7[1-578]|8[2-9]))","9(?:2(?:[23]02|6(?:[25]|4[6-8])|9(?:[02356]|4[02568]|72|8[23]))|3(?:3[28]|4(?:[04679]|3[5-8]|5[4-68]|8[2379])|5(?:[2467]|3[237]|8[2-5])|7[1-578]|8(?:[2469]|3[2578]|5[4-8]|7[36-8]|8[5-8])))|92(?:2[24-9]|3[1-59]|47)","9(?:2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3[78]|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8[23])|7[1-578]|8(?:[2469]|3[278]|5(?:[56][46]|[78])|7[378]|8(?:6[3-6]|[78]))))|92(?:2[24-9]|3[1-59]|47)|93(?:4[35][56]|58[45]|8(?:[38]5|54|76))[4-6]","9(?:2(?:[23]02|6(?:[25]|4(?:64|[78]))|9(?:[02356]|4(?:[0268]|5[2-6])|72|8[23]))|3(?:3[28]|4(?:[04679]|3(?:5(?:4[0-25689]|[56])|[78])|5(?:4[46]|8)|8[2379])|5(?:[2467]|3[237]|8(?:[23]|4(?:[45]|60)|5(?:4[0-39]|5|64)))|7[1-578]|8(?:[2469]|3[278]|5(?:4(?:4|5[13-7]|6[89])|[56][46]|[78])|7[378]|8(?:6[3-6]|[78]))))|92(?:2[24-9]|3[1-59]|47)|93(?:4(?:36|5[56])|8(?:[38]5|76))[4-6]"],"0$1",0,"$1 $2 $3-$4"],["(\\d)(\\d{2})(\\d{4})(\\d{4})","$2 15-$3-$4",["91"],"0$1",0,"$1 $2 $3-$4"],["(\\d{3})(\\d{3})(\\d{5})","$1-$2-$3",["8"],"0$1"],["(\\d)(\\d{3})(\\d{3})(\\d{4})","$2 15-$3-$4",["9"],"0$1",0,"$1 $2 $3-$4"]],"0",0,"0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[0-24-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:[069]|1[1568]|2[15]|3[145]|4[13]|5[14-8]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))15)?","9$1",0,0,[0,["93(?:7(?:1[15]|81)|8(?:21|4[16]|69|9[12]))[46]\\d{5}|9(?:2(?:2(?:2[59]|44|52)|3(?:26|44)|47[35]|9(?:[07]2|2[26]|34|46))|3327)[45]\\d{5}|9(?:2(?:657|9(?:54|66))|3(?:48[27]|7(?:55|77)|8(?:65|78)))[2-8]\\d{5}|9(?:2(?:284|3(?:02|23)|477|622|920)|3(?:4(?:46|89|92)|541))[2-7]\\d{5}|(?:675\\d|9(?:11[1-8]\\d|2(?:2(?:0[45]|1[2-6]|3[3-6])|3(?:[06]4|7[45])|494|6(?:04|1[2-8]|[36][45]|4[3-6])|80[45]|9(?:[17][4-6]|[48][45]|9[3-6]))|3(?:364|4(?:1[2-8]|[25][4-6]|3[3-6]|84)|5(?:1[2-9]|[38][4-6])|6(?:2[45]|44)|7[069][45]|8(?:0[45]|1[2-7]|3[4-6]|5[3-6]|7[2-6]|8[3-68]))))\\d{6}|9(?:2(?:2(?:62|81)|320|9(?:42|83))|3(?:329|4(?:62|7[16])|5(?:43|64)|7(?:18|5[17])))[2-6]\\d{5}|92(?:2(?:21|4[23]|6[145]|7[1-4]|8[356]|9[267])|3(?:16|3[13-8]|43|5[346-8]|9[3-5])|6(?:2[46]|4[78]|5[1568])|9(?:03|2[1457-9]|3[1356]|4[08]|[56][23]|82))4\\d{5}|9(?:2(?:257|3(?:24|46|92)|9(?:01|23|64))|3(?:4(?:42|64)|5(?:25|37|4[47]|71)|7(?:35|72)|825))[3-6]\\d{5}|9(?:2(?:2(?:02|2[3467]|4[156]|5[45]|6[6-8]|91)|3(?:1[47]|25|[45][25]|96)|47[48]|625|932)|3(?:38[2578]|4(?:0[0-24-9]|3[78]|4[457]|58|6[035-9]|72|83|9[136-8])|5(?:2[124]|[368][23]|4[2689]|7[2-6])|7(?:16|2[15]|3[14]|4[13]|5[468]|7[3-5]|8[26])|8(?:2[67]|3[278]|4[3-5]|5[78]|6[1-378]|[78]7|94)))[4-6]\\d{5}"]]],AS:["1","011","(?:[58]\\d\\d|684|900)\\d{7}",[10],0,"1",0,"([267]\\d{6})$|1","684$1",0,"684",[0,["684(?:2(?:48|5[2468]|7[26])|7(?:3[13]|70|82))\\d{4}"]]],AT:["43","00","1\\d{3,12}|2\\d{6,12}|43(?:(?:0\\d|5[02-9])\\d{3,9}|2\\d{4,5}|[3467]\\d{4}|8\\d{4,6}|9\\d{4,7})|5\\d{4,12}|8\\d{7,12}|9\\d{8,12}|(?:[367]\\d|4[0-24-9])\\d{4,11}",[4,5,6,7,8,9,10,11,12,13],[["(\\d)(\\d{3,12})","$1 $2",["1(?:11|[2-9])"],"0$1"],["(\\d{3})(\\d{2})","$1 $2",["517"],"0$1"],["(\\d{2})(\\d{3,5})","$1 $2",["5[079]"],"0$1"],["(\\d{3})(\\d{3,10})","$1 $2",["(?:31|4)6|51|6(?:5[0-3579]|[6-9])|7(?:20|32|8)|[89]"],"0$1"],["(\\d{4})(\\d{3,9})","$1 $2",["[2-467]|5[2-6]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["5"],"0$1"],["(\\d{2})(\\d{4})(\\d{4,7})","$1 $2 $3",["5"],"0$1"]],"0",0,0,0,0,0,[0,["6(?:5[0-3579]|6[013-9]|[7-9]\\d)\\d{4,10}",[7,8,9,10,11,12,13]]]],AU:["61","001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011","1(?:[0-79]\\d{7}(?:\\d(?:\\d{2})?)?|8[0-24-9]\\d{7})|[2-478]\\d{8}|1\\d{4,7}",[5,6,7,8,9,10,12],[["(\\d{2})(\\d{3,4})","$1 $2",["16"],"0$1"],["(\\d{2})(\\d{3})(\\d{2,4})","$1 $2 $3",["16"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["14|4"],"0$1"],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["[2378]"],"(0$1)"],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1(?:30|[89])"]]],"0",0,"(183[12])|0",0,0,0,[0,["4(?:79[01]|83[0-389]|94[0-4])\\d{5}|4(?:[0-36]\\d|4[047-9]|5[0-25-9]|7[02-8]|8[0-24-9]|9[0-37-9])\\d{6}",[9]]],"0011"],AW:["297","00","(?:[25-79]\\d\\d|800)\\d{4}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[25-9]"]]],0,0,0,0,0,0,[0,["(?:290|5[69]\\d|6(?:[03]0|22|4[0-2]|[69]\\d)|7(?:[34]\\d|7[07])|9(?:6[45]|9[4-8]))\\d{4}"]]],AX:["358","00|99(?:[01469]|5(?:[14]1|3[23]|5[59]|77|88|9[09]))","2\\d{4,9}|35\\d{4,5}|(?:60\\d\\d|800)\\d{4,6}|7\\d{5,11}|(?:[14]\\d|3[0-46-9]|50)\\d{4,8}",[5,6,7,8,9,10,11,12],0,"0",0,0,0,0,"18",[0,["4946\\d{2,6}|(?:4[0-8]|50)\\d{4,8}",[6,7,8,9,10]]],"00"],AZ:["994","00","365\\d{6}|(?:[124579]\\d|60|88)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["90"],"0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["1[28]|2|365|46","1[28]|2|365[45]|46","1[28]|2|365(?:4|5[02])|46"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[13-9]"],"0$1"]],"0",0,0,0,0,0,[0,["36554\\d{4}|(?:[16]0|4[04]|5[015]|7[07]|99)\\d{7}"]]],BA:["387","00","6\\d{8}|(?:[35689]\\d|49|70)\\d{6}",[8,9],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["6[1-3]|[7-9]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2-$3",["[3-5]|6[56]"],"0$1"],["(\\d{2})(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3 $4",["6"],"0$1"]],"0",0,0,0,0,0,[0,["6040\\d{5}|6(?:03|[1-356]|44|7\\d)\\d{6}"]]],BB:["1","011","(?:246|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","246$1",0,"246",[0,["246(?:(?:2(?:[3568]\\d|4[0-57-9])|3(?:5[2-9]|6[0-6])|4(?:46|5\\d)|69[5-7]|8(?:[2-5]\\d|83))\\d|52(?:1[147]|20))\\d{3}"]]],BD:["880","00","[1-469]\\d{9}|8[0-79]\\d{7,8}|[2-79]\\d{8}|[2-9]\\d{7}|[3-9]\\d{6}|[57-9]\\d{5}",[6,7,8,9,10],[["(\\d{2})(\\d{4,6})","$1-$2",["31[5-8]|[459]1"],"0$1"],["(\\d{3})(\\d{3,7})","$1-$2",["3(?:[67]|8[013-9])|4(?:6[168]|7|[89][18])|5(?:6[128]|9)|6(?:[15]|28|4[14])|7[2-589]|8(?:0[014-9]|[12])|9[358]|(?:3[2-5]|4[235]|5[2-578]|6[0389]|76|8[3-7]|9[24])1|(?:44|66)[01346-9]"],"0$1"],["(\\d{4})(\\d{3,6})","$1-$2",["[13-9]|2[23]"],"0$1"],["(\\d)(\\d{7,8})","$1-$2",["2"],"0$1"]],"0",0,0,0,0,0,[0,["(?:1[13-9]\\d|644)\\d{7}|(?:3[78]|44|66)[02-9]\\d{7}",[10]]]],BE:["32","00","4\\d{8}|[1-9]\\d{7}",[8,9],[["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["(?:80|9)0"],"0$1"],["(\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[239]|4[23]"],"0$1"],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[15-8]"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["4"],"0$1"]],"0",0,0,0,0,0,[0,["4[5-9]\\d{7}",[9]]]],BF:["226","00","[025-7]\\d{7}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[025-7]"]]],0,0,0,0,0,0,[0,["(?:0[1-7]|5[0-8]|[67]\\d)\\d{6}"]]],BG:["359","00","00800\\d{7}|[2-7]\\d{6,7}|[89]\\d{6,8}|2\\d{5}",[6,7,8,9,12],[["(\\d)(\\d)(\\d{2})(\\d{2})","$1 $2 $3 $4",["2"],"0$1"],["(\\d{3})(\\d{4})","$1 $2",["43[1-6]|70[1-9]"],"0$1"],["(\\d)(\\d{3})(\\d{3,4})","$1 $2 $3",["2"],"0$1"],["(\\d{2})(\\d{3})(\\d{2,3})","$1 $2 $3",["[356]|4[124-7]|7[1-9]|8[1-6]|9[1-7]"],"0$1"],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["(?:70|8)0"],"0$1"],["(\\d{3})(\\d{3})(\\d{2})","$1 $2 $3",["43[1-7]|7"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[48]|9[08]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["9"],"0$1"]],"0",0,0,0,0,0,[0,["(?:43[07-9]|99[69]\\d)\\d{5}|(?:8[7-9]|98)\\d{7}",[8,9]]]],BH:["973","00","[136-9]\\d{7}",[8],[["(\\d{4})(\\d{4})","$1 $2",["[13679]|8[02-4679]"]]],0,0,0,0,0,0,[0,["(?:3(?:[0-79]\\d|8[0-57-9])\\d|6(?:3(?:00|33|6[16])|441|6(?:3[03-9]|[69]\\d|7[0-689])))\\d{4}"]]],BI:["257","00","(?:[267]\\d|31)\\d{6}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2367]"]]],0,0,0,0,0,0,[0,["(?:29|[67][125-9])\\d{6}"]]],BJ:["229","00","(?:01\\d|[24-689])\\d{7}",[8,10],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[24-689]"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5",["0"]]],0,0,0,0,0,0,[0,["(?:01(?:2[5-9]|[4-69]\\d)|4[0-8]|[56]\\d|9[013-9])\\d{6}"]]],BL:["590","00","(?:590\\d|7090)\\d{5}|(?:69|80|9\\d)\\d{7}",[9],0,"0",0,0,0,0,0,[0,["(?:69(?:0\\d\\d|1(?:2[2-9]|3[0-5])|4(?:0[89]|1[2-6]|9\\d)|6(?:1[016-9]|5[0-4]|[67]\\d))|7090[0-4])\\d{4}"]]],BM:["1","011","(?:441|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","441$1",0,"441",[0,["441(?:[2378]\\d|5[0-39]|9[02])\\d{5}"]]],BN:["673","00","[2-578]\\d{6}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[2-578]"]]],0,0,0,0,0,0,[0,["(?:22[89]|[78]\\d\\d)\\d{4}"]]],BO:["591","00(?:1\\d)?","8001\\d{5}|(?:[2-467]\\d|50)\\d{6}",[8,9],[["(\\d)(\\d{7})","$1 $2",["[235]|4[46]"]],["(\\d{8})","$1",["[67]"]],["(\\d{3})(\\d{2})(\\d{4})","$1 $2 $3",["8"]]],"0",0,"0(1\\d)?",0,0,0,[0,["[67]\\d{7}",[8]]]],BQ:["599","00","(?:[34]1|7\\d)\\d{5}",[7],0,0,0,0,0,0,"[347]",[0,["(?:31(?:8[14-8]|9[14578])|416[14-9]|7(?:0[01]|7[07]|8\\d|9[056])\\d)\\d{3}"]]],BR:["55","00(?:1[245]|2[1-35]|31|4[13]|[56]5|99)","(?:[1-46-9]\\d\\d|5(?:[0-46-9]\\d|5[0-46-9]))\\d{8}|[1-9]\\d{9}|[3589]\\d{8}|[34]\\d{7}",[8,9,10,11],[["(\\d{4})(\\d{4})","$1-$2",["300|4(?:0[02]|37)","4(?:02|37)0|[34]00"]],["(\\d{3})(\\d{2,3})(\\d{4})","$1 $2 $3",["(?:[358]|90)0"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3",["(?:[14689][1-9]|2[12478]|3[1-578]|5[13-5]|7[13-579])[2-57]"],"($1)"],["(\\d{2})(\\d{5})(\\d{4})","$1 $2-$3",["[16][1-9]|[2-57-9]"],"($1)"]],"0",0,"(?:0|90)(?:(1[245]|2[1-35]|31|4[13]|[56]5|99)(\\d{10,11}))?","$2",0,0,[0,["(?:[14689][1-9]|2[12478]|3[1-578]|5[13-5]|7[13-579])(?:7|9\\d)\\d{7}",[10,11]]]],BS:["1","011","(?:242|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([3-8]\\d{6})$|1","242$1",0,"242",[0,["242(?:3(?:5[79]|7[56]|95)|4(?:[23][1-9]|4[1-35-9]|5[1-8]|6[2-8]|7\\d|81)|5(?:2[45]|3[35]|44|5[1-46-9]|65|77)|6[34]6|7(?:27|38)|8(?:0[1-9]|1[02-9]|2\\d|3[0-4]|[89]9))\\d{4}"]]],BT:["975","00","[17]\\d{7}|[2-8]\\d{6}",[7,8],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["[2-68]|7[246]"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["1[67]|7"]]],0,0,0,0,0,0,[0,["(?:1[67]|77)\\d{6}",[8]]]],BW:["267","00","(?:0800|(?:[37]|800)\\d)\\d{6}|(?:[2-6]\\d|90)\\d{5}",[7,8,10],[["(\\d{2})(\\d{5})","$1 $2",["90"]],["(\\d{3})(\\d{4})","$1 $2",["[24-6]|3[15-9]"]],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[37]"]],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["0"]],["(\\d{3})(\\d{4})(\\d{3})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["(?:321|7[1-8]\\d)\\d{5}",[8]]]],BY:["375","810","(?:[12]\\d|33|44|902)\\d{7}|8(?:0[0-79]\\d{5,7}|[1-7]\\d{9})|8(?:1[0-489]|[5-79]\\d)\\d{7}|8[1-79]\\d{6,7}|8[0-79]\\d{5}|8\\d{5}",[6,7,8,9,10,11],[["(\\d{3})(\\d{3})","$1 $2",["800"],"8 $1"],["(\\d{3})(\\d{2})(\\d{2,4})","$1 $2 $3",["800"],"8 $1"],["(\\d{4})(\\d{2})(\\d{3})","$1 $2-$3",["1(?:5[169]|6[3-5]|7[179])|2(?:1[35]|2[34]|3[3-5])","1(?:5[169]|6(?:3[1-3]|4|5[125])|7(?:1[3-9]|7[0-24-6]|9[2-7]))|2(?:1[35]|2[34]|3[3-5])"],"8 0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2-$3-$4",["1(?:[56]|7[467])|2[1-3]"],"8 0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2-$3-$4",["[1-4]"],"8 0$1"],["(\\d{3})(\\d{3,4})(\\d{4})","$1 $2 $3",["[89]"],"8 $1"]],"8",0,"0|80?",0,0,0,[0,["(?:2(?:5[5-79]|9[1-9])|(?:33|44)\\d)\\d{6}",[9]]],"8~10"],BZ:["501","00","(?:0800\\d|[2-8])\\d{6}",[7,11],[["(\\d{3})(\\d{4})","$1-$2",["[2-8]"]],["(\\d)(\\d{3})(\\d{4})(\\d{3})","$1-$2-$3-$4",["0"]]],0,0,0,0,0,0,[0,["6[0-35-7]\\d{5}",[7]]]],CA:["1","011","[2-9]\\d{9}|3\\d{6}",[7,10],0,"1",0,0,0,0,0,[0,["(?:2(?:04|[23]6|[48]9|50|63)|3(?:06|43|54|6[578]|82)|4(?:03|1[68]|[26]8|3[178]|50|74)|5(?:06|1[49]|48|79|8[147])|6(?:04|[18]3|39|47|72)|7(?:0[59]|42|53|78|8[02])|8(?:[06]7|19|25|7[39])|9(?:0[25]|42))[2-9]\\d{6}",[10]]]],CC:["61","001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011","1(?:[0-79]\\d{8}(?:\\d{2})?|8[0-24-9]\\d{7})|[148]\\d{8}|1\\d{5,7}",[6,7,8,9,10,12],0,"0",0,"([59]\\d{7})$|0","8$1",0,0,[0,["4(?:79[01]|83[0-389]|94[0-4])\\d{5}|4(?:[0-36]\\d|4[047-9]|5[0-25-9]|7[02-8]|8[0-24-9]|9[0-37-9])\\d{6}",[9]]],"0011"],CD:["243","00","(?:(?:[189]|5\\d)\\d|2)\\d{7}|[1-68]\\d{6}",[7,8,9,10],[["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3",["88"],"0$1"],["(\\d{2})(\\d{5})","$1 $2",["[1-6]"],"0$1"],["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",["2"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["1"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[89]"],"0$1"],["(\\d{2})(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3 $4",["5"],"0$1"]],"0",0,0,0,0,0,[0,["88\\d{5}|(?:8[0-69]|9[017-9])\\d{7}",[7,9]]]],CF:["236","00","(?:[27]\\d{3}|8776)\\d{4}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[278]"]]],0,0,0,0,0,0,[0,["7[024-7]\\d{6}"]]],CG:["242","00","222\\d{6}|(?:0\\d|80)\\d{7}",[9],[["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["8"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[02]"]]],0,0,0,0,0,0,[0,["026(?:1[0-5]|6[6-9])\\d{4}|0(?:[14-6]\\d\\d|2(?:40|5[5-8]|6[07-9]))\\d{5}"]]],CH:["41","00","8\\d{11}|[2-9]\\d{8}",[9,12],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["8[047]|90"],"0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2-79]|81"],"0$1"],["(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:6[89]|7[235-9])\\d{7}",[9]]]],CI:["225","00","[02]\\d{9}",[10],[["(\\d{2})(\\d{2})(\\d)(\\d{5})","$1 $2 $3 $4",["2"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3 $4",["0"]]],0,0,0,0,0,0,[0,["0[157]\\d{8}"]]],CK:["682","00","[2-578]\\d{4}",[5],[["(\\d{2})(\\d{3})","$1 $2",["[2-578]"]]],0,0,0,0,0,0,[0,["[578]\\d{4}"]]],CL:["56","(?:0|1(?:1[0-69]|2[02-5]|5[13-58]|69|7[0167]|8[018]))0","12300\\d{6}|6\\d{9,10}|[2-9]\\d{8}",[9,10,11],[["(\\d{5})(\\d{4})","$1 $2",["219","2196"],"($1)"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["44"]],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["2[1-36]"],"($1)"],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["9[2-9]"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["3[2-5]|[47]|5[1-3578]|6[13-57]|8(?:0[1-9]|[1-9])"],"($1)"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["60|8"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["1"]],["(\\d{3})(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3 $4",["60"]]],0,0,0,0,0,0,[0,["2(?:1982[0-6]|3314[05-9])\\d{3}|(?:2(?:1(?:160|962)|3(?:2\\d\\d|3(?:[03467]\\d|1[0-35-9]|2[1-9]|5[0-24-9]|8[0-3])|600)|646[59])|80[1-9]\\d\\d|9(?:3(?:[0-57-9]\\d\\d|6(?:0[02-9]|[1-9]\\d))|6(?:[0-8]\\d\\d|9(?:[02-79]\\d|1[05-9]))|7[1-9]\\d\\d|9(?:[03-9]\\d\\d|1(?:[0235-9]\\d|4[0-24-9])|2(?:[0-79]\\d|8[0-46-9]))))\\d{4}|(?:22|3[2-5]|[47][1-35]|5[1-3578]|6[13-57]|8[1-9]|9[2458])\\d{7}",[9]]]],CM:["237","00","[26]\\d{8}|88\\d{6,7}",[8,9],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["88"]],["(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5",["[26]|88"]]],0,0,0,0,0,0,[0,["(?:24[23]|6(?:[25-9]\\d|40))\\d{6}",[9]]]],CN:["86","00|1(?:[12]\\d|79)\\d\\d00","(?:(?:1[03-689]|2\\d)\\d\\d|6)\\d{8}|1\\d{10}|[126]\\d{6}(?:\\d(?:\\d{2})?)?|86\\d{5,6}|(?:[3-579]\\d|8[0-57-9])\\d{5,9}",[7,8,9,10,11,12],[["(\\d{2})(\\d{5,6})","$1 $2",["(?:10|2[0-57-9])[19]|3(?:[157]|35|49|9[1-68])|4(?:1[124-9]|2[179]|6[47-9]|7|8[23])|5(?:[1357]|2[37]|4[36]|6[1-46]|80)|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:07|1[236-8]|2[5-7]|[37]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|3|4[13]|5[1-5]|7[0-79]|9[0-35-9])|(?:4[35]|59|85)[1-9]","(?:10|2[0-57-9])(?:1[02]|9[56])|8078|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:1[124-9]|2[179]|[35][1-9]|6[47-9]|7\\d|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|3\\d|4[13]|5[1-5]|7[0-79]|9[0-35-9]))1","10(?:1(?:0|23)|9[56])|2[0-57-9](?:1(?:00|23)|9[56])|80781|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:1[124-9]|2[179]|[35][1-9]|6[47-9]|7\\d|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|3\\d|4[13]|5[1-5]|7[0-79]|9[0-35-9]))12","10(?:1(?:0|23)|9[56])|2[0-57-9](?:1(?:00|23)|9[56])|807812|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:1[124-9]|2[179]|[35][1-9]|6[47-9]|7\\d|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|3\\d|4[13]|5[1-5]|7[0-79]|9[0-35-9]))123","10(?:1(?:0|23)|9[56])|2[0-57-9](?:1(?:00|23)|9[56])|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:1[124-9]|2[179]|[35][1-9]|6[47-9]|7\\d|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:078|1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|3\\d|4[13]|5[1-5]|7[0-79]|9[0-35-9]))123"],"0$1"],["(\\d{3})(\\d{5,6})","$1 $2",["3(?:[157]|35|49|9[1-68])|4(?:[17]|2[179]|6[47-9]|8[23])|5(?:[1357]|2[37]|4[36]|6[1-46]|80)|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])|(?:4[35]|59|85)[1-9]","(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[1-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))[19]","85[23](?:10|95)|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:10|9[56])","85[23](?:100|95)|(?:3(?:[157]\\d|35|49|9[1-68])|4(?:[17]\\d|2[179]|[35][1-9]|6[47-9]|8[23])|5(?:[1357]\\d|2[37]|4[36]|6[1-46]|80|9[1-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]\\d|2[248]|3[014-9]|4[3-6]|6[023689])|8(?:1[236-8]|2[5-7]|[37]\\d|5[14-9]|8[36-8]|9[1-8])|9(?:0[1-3689]|1[1-79]|[379]\\d|4[13]|5[1-5]))(?:100|9[56])"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["(?:4|80)0"]],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["10|2(?:[02-57-9]|1[1-9])","10|2(?:[02-57-9]|1[1-9])","10[0-79]|2(?:[02-57-9]|1[1-79])|(?:10|21)8(?:0[1-9]|[1-9])"],"0$1",1],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["3(?:[3-59]|7[02-68])|4(?:[26-8]|3[3-9]|5[2-9])|5(?:3[03-9]|[468]|7[028]|9[2-46-9])|6|7(?:[0-247]|3[04-9]|5[0-4689]|6[2368])|8(?:[1-358]|9[1-7])|9(?:[013479]|5[1-5])|(?:[34]1|55|79|87)[02-9]"],"0$1",1],["(\\d{3})(\\d{7,8})","$1 $2",["9"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["80"],"0$1",1],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3",["[3-578]"],"0$1",1],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3",["1[3-9]"]],["(\\d{2})(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3 $4",["[12]"],"0$1",1]],"0",0,"(1(?:[12]\\d|79)\\d\\d)|0",0,0,0,[0,["1740[0-5]\\d{6}|1(?:[38]\\d|4[57]|[59][0-35-9]|6[25-7]|7[0-35-8])\\d{8}",[11]]],"00"],CO:["57","00(?:4(?:[14]4|56)|[579])","(?:46|60\\d\\d)\\d{6}|(?:1\\d|[39])\\d{9}",[8,10,11],[["(\\d{4})(\\d{4})","$1 $2",["46"]],["(\\d{3})(\\d{7})","$1 $2",["6|90"],"($1)"],["(\\d{3})(\\d{7})","$1 $2",["3[0-357]|91"]],["(\\d)(\\d{3})(\\d{7})","$1-$2-$3",["1"],"0$1",0,"$1 $2 $3"]],"0",0,"0([3579]|4(?:[14]4|56))?",0,0,0,[0,["333301[0-5]\\d{3}|3333(?:00|2[5-9]|[3-9]\\d)\\d{4}|(?:3(?:24[1-9]|3(?:00|3[0-24-9]))|9101)\\d{6}|3(?:0[0-5]|1\\d|2[0-3]|5[01]|70)\\d{7}",[10]]]],CR:["506","00","(?:8\\d|90)\\d{8}|(?:[24-8]\\d{3}|3005)\\d{4}",[8,10],[["(\\d{4})(\\d{4})","$1 $2",["[2-7]|8[3-9]"]],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["[89]"]]],0,0,"(19(?:0[0-2468]|1[09]|20|66|77|99))",0,0,0,[0,["(?:3005\\d|6500[01])\\d{3}|(?:5[07]|6[0-4]|7[0-3]|8[3-9])\\d{6}",[8]]]],CU:["53","119","(?:[2-7]|8\\d\\d)\\d{7}|[2-47]\\d{6}|[34]\\d{5}",[6,7,8,10],[["(\\d{2})(\\d{4,6})","$1 $2",["2[1-4]|[34]"],"(0$1)"],["(\\d)(\\d{6,7})","$1 $2",["7"],"(0$1)"],["(\\d)(\\d{7})","$1 $2",["[56]"],"0$1"],["(\\d{3})(\\d{7})","$1 $2",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:5\\d|6[2-4])\\d{6}",[8]]]],CV:["238","0","(?:[2-59]\\d\\d|800)\\d{4}",[7],[["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3",["[2-589]"]]],0,0,0,0,0,0,[0,["(?:36|5[1-389]|9\\d)\\d{5}"]]],CW:["599","00","(?:[34]1|60|(?:7|9\\d)\\d)\\d{5}",[7,8],[["(\\d{3})(\\d{4})","$1 $2",["[3467]"]],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["9[4-8]"]]],0,0,0,0,0,"[69]",[0,["953[01]\\d{4}|9(?:5[12467]|6[5-9])\\d{5}"]]],CX:["61","001[14-689]|14(?:1[14]|34|4[17]|[56]6|7[47]|88)0011","1(?:[0-79]\\d{8}(?:\\d{2})?|8[0-24-9]\\d{7})|[148]\\d{8}|1\\d{5,7}",[6,7,8,9,10,12],0,"0",0,"([59]\\d{7})$|0","8$1",0,0,[0,["4(?:79[01]|83[0-389]|94[0-4])\\d{5}|4(?:[0-36]\\d|4[047-9]|5[0-25-9]|7[02-8]|8[0-24-9]|9[0-37-9])\\d{6}",[9]]],"0011"],CY:["357","00","(?:[279]\\d|[58]0)\\d{6}",[8],[["(\\d{2})(\\d{6})","$1 $2",["[257-9]"]]],0,0,0,0,0,0,[0,["9(?:10|[4-79]\\d)\\d{5}"]]],CZ:["420","00","(?:[2-578]\\d|60)\\d{7}|9\\d{8,11}",[9,10,11,12],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[2-8]|9[015-7]"]],["(\\d{2})(\\d{3})(\\d{3})(\\d{2})","$1 $2 $3 $4",["96"]],["(\\d{2})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["9"]],["(\\d{3})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["9"]]],0,0,0,0,0,0,[0,["(?:60[1-8]\\d|7(?:0(?:[2-5]\\d|60)|19[0-2]|[2379]\\d\\d))\\d{5}",[9]]]],DE:["49","00","[2579]\\d{5,14}|49(?:[34]0|69|8\\d)\\d\\d?|49(?:37|49|60|7[089]|9\\d)\\d{1,3}|49(?:2[024-9]|3[2-689]|7[1-7])\\d{1,8}|(?:1|[368]\\d|4[0-8])\\d{3,13}|49(?:[015]\\d|2[13]|31|[46][1-8])\\d{1,9}",[4,5,6,7,8,9,10,11,12,13,14,15],[["(\\d{2})(\\d{3,13})","$1 $2",["3[02]|40|[68]9"],"0$1"],["(\\d{3})(\\d{3,12})","$1 $2",["2(?:0[1-389]|1[124]|2[18]|3[14])|3(?:[35-9][15]|4[015])|906|(?:2[4-9]|4[2-9]|[579][1-9]|[68][1-8])1","2(?:0[1-389]|12[0-8])|3(?:[35-9][15]|4[015])|906|2(?:[13][14]|2[18])|(?:2[4-9]|4[2-9]|[579][1-9]|[68][1-8])1"],"0$1"],["(\\d{4})(\\d{2,11})","$1 $2",["[24-6]|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])|70[2-8]|8(?:0[2-9]|[1-8])|90[7-9]|[79][1-9]","[24-6]|3(?:3(?:0[1-467]|2[127-9]|3[124578]|7[1257-9]|8[1256]|9[145])|4(?:2[135]|4[13578]|9[1346])|5(?:0[14]|2[1-3589]|6[1-4]|7[13468]|8[13568])|6(?:2[1-489]|3[124-6]|6[13]|7[12579]|8[1-356]|9[135])|7(?:2[1-7]|4[145]|6[1-5]|7[1-4])|8(?:21|3[1468]|6|7[1467]|8[136])|9(?:0[12479]|2[1358]|4[134679]|6[1-9]|7[136]|8[147]|9[1468]))|70[2-8]|8(?:0[2-9]|[1-8])|90[7-9]|[79][1-9]|3[68]4[1347]|3(?:47|60)[1356]|3(?:3[46]|46|5[49])[1246]|3[4579]3[1357]"],"0$1"],["(\\d{3})(\\d{4})","$1 $2",["138"],"0$1"],["(\\d{5})(\\d{2,10})","$1 $2",["3"],"0$1"],["(\\d{3})(\\d{5,11})","$1 $2",["181"],"0$1"],["(\\d{3})(\\d)(\\d{4,10})","$1 $2 $3",["1(?:3|80)|9"],"0$1"],["(\\d{3})(\\d{7,8})","$1 $2",["1[67]"],"0$1"],["(\\d{3})(\\d{7,12})","$1 $2",["8"],"0$1"],["(\\d{5})(\\d{6})","$1 $2",["185","1850","18500"],"0$1"],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3",["7"],"0$1"],["(\\d{4})(\\d{7})","$1 $2",["18[68]"],"0$1"],["(\\d{4})(\\d{7})","$1 $2",["15[1279]"],"0$1"],["(\\d{5})(\\d{6})","$1 $2",["15[03568]","15(?:[0568]|31)"],"0$1"],["(\\d{3})(\\d{8})","$1 $2",["18"],"0$1"],["(\\d{3})(\\d{2})(\\d{7,8})","$1 $2 $3",["1(?:6[023]|7)"],"0$1"],["(\\d{4})(\\d{2})(\\d{7})","$1 $2 $3",["15[279]"],"0$1"],["(\\d{3})(\\d{2})(\\d{8})","$1 $2 $3",["15"],"0$1"]],"0",0,0,0,0,0,[0,["1(?:(?:5(?:[0-25-9]\\d\\d|310)|76\\d\\d)\\d{6}|6[023]\\d{7,8})|17\\d{8}",[10,11]]]],DJ:["253","00","(?:2\\d|77)\\d{6}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[27]"]]],0,0,0,0,0,0,[0,["77\\d{6}"]]],DK:["45","00","[2-9]\\d{7}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2-9]"]]],0,0,0,0,0,0,[0,["(?:2[6-8]|37|6[78]|96)\\d{6}|(?:2[0-59]|3[0-689]|[457]\\d|6[0-69]|8[126-9]|9[1-47-9])[1-9]\\d{5}"]]],DM:["1","011","(?:[58]\\d\\d|767|900)\\d{7}",[10],0,"1",0,"([2-7]\\d{6})$|1","767$1",0,"767",[0,["767(?:2(?:[2-4689]5|7[5-7])|31[5-7]|61[1-8]|70[1-6])\\d{4}"]]],DO:["1","011","(?:[58]\\d\\d|900)\\d{7}",[10],0,"1",0,0,0,0,"8001|8[024]9",[0,["8[024]9[2-9]\\d{6}"]]],DZ:["213","00","(?:[1-4]|[5-79]\\d|80)\\d{7}",[8,9],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[1-4]"],"0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["9"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-8]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:5(?:4[0-29]|5\\d|6[0-3])|6(?:[569]\\d|7[0-6])|7[7-9]\\d)\\d{6}",[9]]]],EC:["593","00","1\\d{9,10}|(?:[2-7]|9\\d)\\d{7}",[8,9,10,11],[["(\\d)(\\d{3})(\\d{4})","$1 $2-$3",["[2-7]"],"(0$1)",0,"$1-$2-$3"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["9"],"0$1"],["(\\d{4})(\\d{3})(\\d{3,4})","$1 $2 $3",["1"]]],"0",0,0,0,0,0,[0,["964[0-2]\\d{5}|9(?:39|[57][89]|6[0-36-9]|[89]\\d)\\d{6}",[9]]]],EE:["372","00","8\\d{9}|[4578]\\d{7}|(?:[3-8]\\d|90)\\d{5}",[7,8,10],[["(\\d{3})(\\d{4})","$1 $2",["[369]|4[3-8]|5(?:[0-2]|5[0-478]|6[45])|7[1-9]|88","[369]|4[3-8]|5(?:[02]|1(?:[0-8]|95)|5[0-478]|6(?:4[0-4]|5[1-589]))|7[1-9]|88"]],["(\\d{4})(\\d{3,4})","$1 $2",["[45]|8(?:00|[1-49])","[45]|8(?:00[1-9]|[1-49])"]],["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",["7"]],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["(?:5\\d{5}|8(?:1(?:0(?:0(?:00|[178]\\d)|[3-9]\\d\\d)|(?:1(?:0[2-6]|1\\d)|(?:2[0-59]|[3-79]\\d)\\d)\\d)|2(?:0(?:0(?:00|4\\d)|(?:19|[2-7]\\d)\\d)|(?:(?:[124-69]\\d|3[5-9])\\d|7(?:[0-79]\\d|8[13-9])|8(?:[2-6]\\d|7[01]))\\d)|[349]\\d{4}))\\d\\d|5(?:(?:[02]\\d|5[0-478])\\d|1(?:[0-8]\\d|95)|6(?:4[0-4]|5[1-589]))\\d{3}",[7,8]]]],EG:["20","00","[189]\\d{8,9}|[24-6]\\d{8}|[135]\\d{7}",[8,9,10],[["(\\d)(\\d{7,8})","$1 $2",["[23]"],"0$1"],["(\\d{2})(\\d{6,7})","$1 $2",["1[35]|[4-6]|8[2468]|9[235-7]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[89]"],"0$1"],["(\\d{2})(\\d{8})","$1 $2",["1"],"0$1"]],"0",0,0,0,0,0,[0,["1[0-25]\\d{8}",[10]]]],EH:["212","00","[5-8]\\d{8}",[9],0,"0",0,0,0,0,"528[89]",[0,["(?:6(?:[0-79]\\d|8[0-247-9])|7(?:[0167]\\d|2[0-467]|5[0-3]|8[0-5]))\\d{6}"]]],ER:["291","00","[178]\\d{6}",[7],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["[178]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:17[1-3]|7\\d\\d)\\d{4}"]]],ES:["34","00","[5-9]\\d{8}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[89]00"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-9]"]]],0,0,0,0,0,0,[0,["(?:590[16]00\\d|9(?:6906(?:09|10)|7390\\d\\d))\\d\\d|(?:6\\d|7[1-48])\\d{7}"]]],ET:["251","00","(?:11|[2-579]\\d)\\d{7}",[9],[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[1-579]"],"0$1"]],"0",0,0,0,0,0,[0,["700[1-9]\\d{5}|(?:7(?:0[1-9]|1[0-8]|22|77|86|99)|9\\d\\d)\\d{6}"]]],FI:["358","00|99(?:[01469]|5(?:[14]1|3[23]|5[59]|77|88|9[09]))","[1-35689]\\d{4}|7\\d{10,11}|(?:[124-7]\\d|3[0-46-9])\\d{8}|[1-9]\\d{5,8}",[5,6,7,8,9,10,11,12],[["(\\d{5})","$1",["20[2-59]"],"0$1"],["(\\d{3})(\\d{3,7})","$1 $2",["(?:[1-3]0|[68])0|70[07-9]"],"0$1"],["(\\d{2})(\\d{4,8})","$1 $2",["[14]|2[09]|50|7[135]"],"0$1"],["(\\d{2})(\\d{6,10})","$1 $2",["7"],"0$1"],["(\\d)(\\d{4,9})","$1 $2",["(?:19|[2568])[1-8]|3(?:0[1-9]|[1-9])|9"],"0$1"]],"0",0,0,0,0,"1[03-79]|[2-9]",[0,["4946\\d{2,6}|(?:4[0-8]|50)\\d{4,8}",[6,7,8,9,10]]],"00"],FJ:["679","0(?:0|52)","45\\d{5}|(?:0800\\d|[235-9])\\d{6}",[7,11],[["(\\d{3})(\\d{4})","$1 $2",["[235-9]|45"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["0"]]],0,0,0,0,0,0,[0,["(?:[279]\\d|45|5[01568]|8[034679])\\d{5}",[7]]],"00"],FK:["500","00","[2-7]\\d{4}",[5],0,0,0,0,0,0,0,[0,["[56]\\d{4}"]]],FM:["691","00","(?:[39]\\d\\d|820)\\d{4}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[389]"]]],0,0,0,0,0,0,[0,["31(?:00[67]|208|309)\\d\\d|(?:3(?:[2357]0[1-9]|602|804|905)|(?:820|9[2-7]\\d)\\d)\\d{3}"]]],FO:["298","00","[2-9]\\d{5}",[6],[["(\\d{6})","$1",["[2-9]"]]],0,0,"(10(?:01|[12]0|88))",0,0,0,[0,["(?:[27][1-9]|5\\d|9[16])\\d{4}"]]],FR:["33","00","[1-9]\\d{8}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"],"0 $1"],["(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5",["[1-79]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:6(?:[0-24-8]\\d|3[0-8]|9[589])|7[3-9]\\d)\\d{6}"]]],GA:["241","00","(?:[067]\\d|11)\\d{6}|[2-7]\\d{6}",[7,8],[["(\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2-7]"],"0$1"],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["0"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["11|[67]"],"0$1"]],0,0,"0(11\\d{6}|60\\d{6}|61\\d{6}|6[256]\\d{6}|7[467]\\d{6})","$1",0,0,[0,["(?:(?:0[2-7]|7[467])\\d|6(?:0[0-4]|10|[256]\\d))\\d{5}|[2-7]\\d{6}"]]],GB:["44","00","[1-357-9]\\d{9}|[18]\\d{8}|8\\d{6}",[7,9,10],[["(\\d{3})(\\d{4})","$1 $2",["800","8001","80011","800111","8001111"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3",["845","8454","84546","845464"],"0$1"],["(\\d{3})(\\d{6})","$1 $2",["800"],"0$1"],["(\\d{5})(\\d{4,5})","$1 $2",["1(?:38|5[23]|69|76|94)","1(?:(?:38|69)7|5(?:24|39)|768|946)","1(?:3873|5(?:242|39[4-6])|(?:697|768)[347]|9467)"],"0$1"],["(\\d{4})(\\d{5,6})","$1 $2",["1(?:[2-69][02-9]|[78])"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["[25]|7(?:0|6[02-9])","[25]|7(?:0|6(?:[03-9]|2[356]))"],"0$1"],["(\\d{4})(\\d{6})","$1 $2",["7"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[1389]"],"0$1"]],"0",0,0,0,0,0,[0,["7(?:457[0-57-9]|700[01]|911[028])\\d{5}|7(?:[1-3]\\d\\d|4(?:[0-46-9]\\d|5[0-689])|5(?:0[0-8]|[13-9]\\d|2[0-35-9])|7(?:0[1-9]|[1-7]\\d|8[02-9]|9[0-689])|8(?:[014-9]\\d|[23][0-8])|9(?:[024-9]\\d|1[02-9]|3[0-689]))\\d{6}",[10]]],0," x"],GD:["1","011","(?:473|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","473$1",0,"473",[0,["473(?:4(?:0[2-79]|1[04-9]|2[0-5]|49|5[68])|5(?:2[01]|3[3-8])|901)\\d{4}"]]],GE:["995","00","(?:[3-57]\\d\\d|800)\\d{6}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["70"],"0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["32"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[57]"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[348]"],"0$1"]],"0",0,0,0,0,0,[0,["5(?:(?:(?:0555|1(?:[17]77|555))[5-9]|757(?:7[7-9]|8[01]))\\d|22252[0-4])\\d\\d|5(?:0(?:0[17]0|505)|1(?:0[01]0|1(?:07|33|51))|2(?:0[02]0|2[25]2)|3(?:0[03]0|3[35]3)|(?:40[04]|900)0|5222)[0-4]\\d{3}|(?:5(?:0(?:0(?:0\\d|11|22|3[0-6]|44|5[05]|77|88|9[09])|(?:[14]\\d|77)\\d|22[02])|1(?:1(?:[03][01]|[124]\\d|5[2-6]|7[0-4])|4\\d\\d)|[23]555|4(?:4\\d\\d|555)|5(?:[0157-9]\\d\\d|200|333|444)|6[89]\\d\\d|7(?:[0147-9]\\d\\d|5(?:00|[57]5))|8(?:0(?:[018]\\d|2[0-4])|5(?:55|8[89])|8(?:55|88))|9(?:090|[1-35-9]\\d\\d))|790\\d\\d)\\d{4}"]]],GF:["594","00","(?:[56]94\\d|7093)\\d{5}|(?:80|9\\d)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-7]|9[47]"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[89]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:694(?:[0-249]\\d|3[0-8])|7093[0-3])\\d{4}"]]],GG:["44","00","(?:1481|[357-9]\\d{3})\\d{6}|8\\d{6}(?:\\d{2})?",[7,9,10],0,"0",0,"([25-9]\\d{5})$|0","1481$1",0,0,[0,["7(?:(?:781|839)\\d|911[17])\\d{5}",[10]]]],GH:["233","00","(?:[235]\\d{3}|800)\\d{5}",[8,9],[["(\\d{3})(\\d{5})","$1 $2",["8"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[235]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:2(?:[0346-9]\\d|5[67])|5(?:[03-7]\\d|9[1-9]))\\d{6}",[9]]]],GI:["350","00","(?:[25]\\d|60)\\d{6}",[8],[["(\\d{3})(\\d{5})","$1 $2",["2"]]],0,0,0,0,0,0,[0,["5251[0-4]\\d{3}|(?:5(?:[146-8]\\d\\d|250)|60(?:1[01]|6\\d))\\d{4}"]]],GL:["299","00","(?:19|[2-689]\\d|70)\\d{4}",[6],[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",["19|[2-9]"]]],0,0,0,0,0,0,[0,["[245]\\d{5}"]]],GM:["220","00","[2-9]\\d{6}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[2-9]"]]],0,0,0,0,0,0,[0,["(?:[23679]\\d|4[015]|5[0-489])\\d{5}"]]],GN:["224","00","722\\d{6}|(?:3|6\\d)\\d{7}",[8,9],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["3"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[67]"]]],0,0,0,0,0,0,[0,["6[0-356]\\d{7}",[9]]]],GP:["590","00","(?:590\\d|7090)\\d{5}|(?:69|80|9\\d)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-79]"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:69(?:0\\d\\d|1(?:2[2-9]|3[0-5])|4(?:0[89]|1[2-6]|9\\d)|6(?:1[016-9]|5[0-4]|[67]\\d))|7090[0-4])\\d{4}"]]],GQ:["240","00","222\\d{6}|(?:3\\d|55|[89]0)\\d{7}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[235]"]],["(\\d{3})(\\d{6})","$1 $2",["[89]"]]],0,0,0,0,0,0,[0,["(?:222|55\\d)\\d{6}"]]],GR:["30","00","5005000\\d{3}|8\\d{9,11}|(?:[269]\\d|70)\\d{8}",[10,11,12],[["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["21|7"]],["(\\d{4})(\\d{6})","$1 $2",["2(?:2|3[2-57-9]|4[2-469]|5[2-59]|6[2-9]|7[2-69]|8[2-49])|5"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[2689]"]],["(\\d{3})(\\d{3,4})(\\d{5})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["68[57-9]\\d{7}|(?:69|94)\\d{8}",[10]]]],GT:["502","00","80\\d{6}|(?:1\\d{3}|[2-7])\\d{7}",[8,11],[["(\\d{4})(\\d{4})","$1 $2",["[2-8]"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["1"]]],0,0,0,0,0,0,[0,["(?:[3-5]\\d\\d|80[0-4])\\d{5}",[8]]]],GU:["1","011","(?:[58]\\d\\d|671|900)\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","671$1",0,"671",[0,["671(?:2\\d\\d|3(?:00|3[39]|4[349]|55|6[26])|4(?:00|56|7[1-9]|8[02-9])|5(?:55|6[2-5]|88)|6(?:3[2-578]|4[24-9]|5[34]|78|8[235-9])|7(?:[0479]7|2[0167]|3[45]|8[7-9])|8(?:[2-57-9]8|6[478])|9(?:2[29]|6[79]|7[1279]|8[7-9]|9[78]))\\d{4}"]]],GW:["245","00","[49]\\d{8}|4\\d{6}",[7,9],[["(\\d{3})(\\d{4})","$1 $2",["40"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[49]"]]],0,0,0,0,0,0,[0,["9(?:5\\d|6[569]|77)\\d{6}",[9]]]],GY:["592","001","(?:[2-8]\\d{3}|9008)\\d{3}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[2-9]"]]],0,0,0,0,0,0,[0,["(?:510|6\\d\\d|7(?:[0-5]\\d|6[01]))\\d{4}"]]],HK:["852","00(?:30|5[09]|[126-9]?)","8[0-46-9]\\d{6,7}|9\\d{4,7}|(?:[2-7]|9\\d{3})\\d{7}",[5,6,7,8,9,11],[["(\\d{3})(\\d{2,5})","$1 $2",["900","9003"]],["(\\d{4})(\\d{4})","$1 $2",["[2-7]|8[1-4]|9(?:0[1-9]|[1-8])"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["8"]],["(\\d{3})(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3 $4",["9"]]],0,0,0,0,0,0,[0,["(?:4(?:44[0-35-9]|6(?:1[0-79]|4[0-57-9]|6[0-4])|7(?:4[0-28]|6[0-5]))|5(?:73[0-6]|95[0-8])|6(?:26[013-8]|66[0-3])|70(?:7[1-8]|8[0-4])|84(?:4[0-2]|8[0-35-9])|9(?:29[013-9]|39[014-9]|59[0-4]|899))\\d{4}|(?:4(?:4[0-35-9]|6[02357-9]|7[015])|5(?:[1-59][0-46-9]|6[0-4689]|7[0-246-9])|6(?:0[1-9]|[13-59]\\d|[268][0-57-9]|7[0-79])|70[1-59]|84[0-39]|9(?:0[1-9]|1[02-9]|[2358][0-8]|[467]\\d))\\d{5}",[8]]],"00"],HN:["504","00","8\\d{10}|[237-9]\\d{7}",[8,11],[["(\\d{4})(\\d{4})","$1-$2",["[237-9]"]]],0,0,0,0,0,0,[0,["[37-9]\\d{7}",[8]]]],HR:["385","00","(?:[24-69]\\d|3[0-79])\\d{7}|80\\d{5,7}|[1-79]\\d{7}|6\\d{5,6}",[6,7,8,9],[["(\\d{2})(\\d{2})(\\d{2,3})","$1 $2 $3",["6[01]"],"0$1"],["(\\d{3})(\\d{2})(\\d{2,3})","$1 $2 $3",["8"],"0$1"],["(\\d)(\\d{4})(\\d{3})","$1 $2 $3",["1"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["6|7[245]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["9"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[2-57]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["8"],"0$1"]],"0",0,0,0,0,0,[0,["9(?:(?:0[1-9]|[12589]\\d)\\d\\d|7(?:[0679]\\d\\d|5(?:[01]\\d|44|55|77|9[5-79])))\\d{4}|98\\d{6}",[8,9]]]],HT:["509","00","(?:[2-489]\\d|55)\\d{6}",[8],[["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",["[2-589]"]]],0,0,0,0,0,0,[0,["(?:[34]\\d|55)\\d{6}"]]],HU:["36","00","[235-7]\\d{8}|[1-9]\\d{7}",[8,9],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["1"],"(06 $1)"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[27][2-9]|3[2-7]|4[24-9]|5[2-79]|6|8[2-57-9]|9[2-69]"],"(06 $1)"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[2-9]"],"06 $1"]],"06",0,0,0,0,0,[0,["(?:[257]0|3[01])\\d{7}",[9]]]],ID:["62","00[89]","00[1-9]\\d{9,14}|(?:[1-36]|8\\d{5})\\d{6}|00\\d{9}|[1-9]\\d{8,10}|[2-9]\\d{7}",[7,8,9,10,11,12,13,14,15,16,17],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["15"]],["(\\d{2})(\\d{5,9})","$1 $2",["2[124]|[36]1"],"(0$1)"],["(\\d{3})(\\d{5,7})","$1 $2",["800"],"0$1"],["(\\d{3})(\\d{5,8})","$1 $2",["[2-79]"],"(0$1)"],["(\\d{3})(\\d{3,4})(\\d{3})","$1-$2-$3",["8[1-35-9]"],"0$1"],["(\\d{3})(\\d{6,8})","$1 $2",["1"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["804"],"0$1"],["(\\d{3})(\\d)(\\d{3})(\\d{3})","$1 $2 $3 $4",["80"],"0$1"],["(\\d{3})(\\d{4})(\\d{4,5})","$1-$2-$3",["8"],"0$1"]],"0",0,0,0,0,0,[0,["8[1-35-9]\\d{7,10}",[9,10,11,12]]]],IE:["353","00","(?:1\\d|[2569])\\d{6,8}|4\\d{6,9}|7\\d{8}|8\\d{8,9}",[7,8,9,10],[["(\\d{2})(\\d{5})","$1 $2",["2[24-9]|47|58|6[237-9]|9[35-9]"],"(0$1)"],["(\\d{3})(\\d{5})","$1 $2",["[45]0"],"(0$1)"],["(\\d)(\\d{3,4})(\\d{4})","$1 $2 $3",["1"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[2569]|4[1-69]|7[14]"],"(0$1)"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["70"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["81"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[78]"],"0$1"],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1"]],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["4"],"(0$1)"],["(\\d{2})(\\d)(\\d{3})(\\d{4})","$1 $2 $3 $4",["8"],"0$1"]],"0",0,0,0,0,0,[0,["8(?:22|[35-9]\\d)\\d{6}",[9]]]],IL:["972","0(?:0|1[2-9])","1\\d{6}(?:\\d{3,5})?|[57]\\d{8}|[1-489]\\d{7}",[7,8,9,10,11,12],[["(\\d{4})(\\d{3})","$1-$2",["125"]],["(\\d{4})(\\d{2})(\\d{2})","$1-$2-$3",["121"]],["(\\d)(\\d{3})(\\d{4})","$1-$2-$3",["[2-489]"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3",["[57]"],"0$1"],["(\\d{4})(\\d{3})(\\d{3})","$1-$2-$3",["12"]],["(\\d{4})(\\d{6})","$1-$2",["159"]],["(\\d)(\\d{3})(\\d{3})(\\d{3})","$1-$2-$3-$4",["1[7-9]"]],["(\\d{3})(\\d{1,2})(\\d{3})(\\d{4})","$1-$2 $3-$4",["15"]]],"0",0,0,0,0,0,[0,["55(?:4(?:[01]0|5[0-2])|57[0-289])\\d{4}|5(?:(?:[0-2][02-9]|[36]\\d|[49][2-9]|8[3-7])\\d|5(?:01|2\\d|3[0-3]|4[34]|5[0-25689]|6[6-8]|7[0-267]|8[7-9]|9[1-9]))\\d{5}",[9]]]],IM:["44","00","1624\\d{6}|(?:[3578]\\d|90)\\d{8}",[10],0,"0",0,"([25-8]\\d{5})$|0","1624$1",0,"74576|(?:16|7[56])24",[0,["76245[06]\\d{4}|7(?:4576|[59]24\\d|624[0-4689])\\d{5}"]]],IN:["91","00","(?:000800|[2-9]\\d\\d)\\d{7}|1\\d{7,12}",[8,9,10,11,12,13],[["(\\d{8})","$1",["5(?:0|2[23]|3[03]|[67]1|88)","5(?:0|2(?:21|3)|3(?:0|3[23])|616|717|888)","5(?:0|2(?:21|3)|3(?:0|3[23])|616|717|8888)"],0,1],["(\\d{4})(\\d{4,5})","$1 $2",["180","1800"],0,1],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["140"],0,1],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["11|2[02]|33|4[04]|79[1-7]|80[2-46]","11|2[02]|33|4[04]|79(?:[1-6]|7[19])|80(?:[2-4]|6[0-589])","11|2[02]|33|4[04]|79(?:[124-6]|3(?:[02-9]|1[0-24-9])|7(?:1|9[1-6]))|80(?:[2-4]|6[0-589])"],"0$1",1],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["1(?:2[0-249]|3[0-25]|4[145]|[68]|7[1257])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|5[12]|[78]1)|6(?:12|[2-4]1|5[17]|6[13]|80)|7(?:12|3[134]|4[47]|61|88)|8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)|(?:43|59|75)[15]|(?:1[59]|29|67|72)[14]","1(?:2[0-24]|3[0-25]|4[145]|[59][14]|6[1-9]|7[1257]|8[1-57-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[058]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|[578]1|9[15])|674|7(?:(?:2[14]|3[34]|5[15])[2-6]|61[346]|88[0-8])|8(?:70[2-6]|84[235-7]|91[3-7])|(?:1(?:29|60|8[06])|261|552|6(?:12|[2-47]1|5[17]|6[13]|80)|7(?:12|31|4[47])|8(?:16|2[014]|3[126]|6[136]|7[78]|83))[2-7]","1(?:2[0-24]|3[0-25]|4[145]|[59][14]|6[1-9]|7[1257]|8[1-57-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[058]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[0-26-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:1[025]|22|[36][25]|4[28]|[578]1|9[15])|6(?:12(?:[2-6]|7[0-8])|74[2-7])|7(?:(?:2[14]|5[15])[2-6]|3171|61[346]|88(?:[2-7]|82))|8(?:70[2-6]|84(?:[2356]|7[19])|91(?:[3-6]|7[19]))|73[134][2-6]|(?:74[47]|8(?:16|2[014]|3[126]|6[136]|7[78]|83))(?:[2-6]|7[19])|(?:1(?:29|60|8[06])|261|552|6(?:[2-4]1|5[17]|6[13]|7(?:1|4[0189])|80)|7(?:12|88[01]))[2-7]"],"0$1",1],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1(?:[2-479]|5[0235-9])|[2-5]|6(?:1[1358]|2[2457-9]|3[2-5]|4[235-7]|5[2-689]|6[24578]|7[235689]|8[1-6])|7(?:1[013-9]|28|3[129]|4[1-35689]|5[29]|6[02-5]|70)|807","1(?:[2-479]|5[0235-9])|[2-5]|6(?:1[1358]|2(?:[2457]|84|95)|3(?:[2-4]|55)|4[235-7]|5[2-689]|6[24578]|7[235689]|8[1-6])|7(?:1(?:[013-8]|9[6-9])|28[6-8]|3(?:17|2[0-49]|9[2-57])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4|5[0-367])|70[13-7])|807[19]","1(?:[2-479]|5(?:[0236-9]|5[013-9]))|[2-5]|6(?:2(?:84|95)|355|83)|73179|807(?:1|9[1-3])|(?:1552|6(?:1[1358]|2[2457]|3[2-4]|4[235-7]|5[2-689]|6[24578]|7[235689]|8[124-6])\\d|7(?:1(?:[013-8]\\d|9[6-9])|28[6-8]|3(?:2[0-49]|9[2-57])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]\\d|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4\\d|5[0-367])|70[13-7]))[2-7]"],"0$1",1],["(\\d{5})(\\d{5})","$1 $2",["[6-9]"],"0$1",1],["(\\d{4})(\\d{2,4})(\\d{4})","$1 $2 $3",["1(?:6|8[06])","1(?:6|8[06]0)"],0,1],["(\\d{4})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["18"],0,1]],"0",0,0,0,0,0,[0,["(?:61279|7(?:887[02-9]|9(?:313|79[07-9]))|8(?:079[04-9]|(?:84|91)7[02-8]))\\d{5}|(?:6(?:12|[2-47]1|5[17]|6[13]|80)[0189]|7(?:1(?:2[0189]|9[0-5])|2(?:[14][017-9]|8[0-59])|3(?:2[5-8]|[34][017-9]|9[016-9])|4(?:1[015-9]|[29][89]|39|8[389])|5(?:[15][017-9]|2[04-9]|9[7-9])|6(?:0[0-47]|1[0-257-9]|2[0-4]|3[19]|5[4589])|70[0289]|88[089]|97[02-8])|8(?:0(?:6[67]|7[02-8])|70[017-9]|84[01489]|91[0-289]))\\d{6}|(?:7(?:31|4[47])|8(?:16|2[014]|3[126]|6[136]|7[78]|83))(?:[0189]\\d|7[02-8])\\d{5}|(?:6(?:[09]\\d|1[04679]|2[03689]|3[05-9]|4[0489]|50|6[069]|7[07]|8[7-9])|7(?:0\\d|2[0235-79]|3[05-8]|40|5[0346-8]|6[6-9]|7[1-9]|8[0-79]|9[089])|8(?:0[01589]|1[0-57-9]|2[235-9]|3[03-57-9]|[45]\\d|6[02457-9]|7[1-69]|8[0-25-9]|9[02-9])|9\\d\\d)\\d{7}|(?:6(?:(?:1[1358]|2[2457]|3[2-4]|4[235-7]|5[2-689]|6[24578]|8[124-6])\\d|7(?:[235689]\\d|4[0189]))|7(?:1(?:[013-8]\\d|9[6-9])|28[6-8]|3(?:2[0-49]|9[2-5])|4(?:1[2-4]|[29][0-7]|3[0-8]|[56]\\d|8[0-24-7])|5(?:2[1-3]|9[0-6])|6(?:0[5689]|2[5-9]|3[02-8]|4\\d|5[0-367])|70[13-7]|881))[0189]\\d{5}",[10]]]],IO:["246","00","3\\d{6}",[7],[["(\\d{3})(\\d{4})","$1 $2",["3"]]],0,0,0,0,0,0,[0,["38\\d{5}"]]],IQ:["964","00","(?:1|7\\d\\d)\\d{7}|[2-6]\\d{7,8}",[8,9,10],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["1"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[2-6]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["7"],"0$1"]],"0",0,0,0,0,0,[0,["7[3-9]\\d{8}",[10]]]],IR:["98","00","[1-9]\\d{9}|(?:[1-8]\\d\\d|9)\\d{3,4}",[4,5,6,7,10],[["(\\d{4,5})","$1",["96"],"0$1"],["(\\d{2})(\\d{4,5})","$1 $2",["(?:1[137]|2[13-68]|3[1458]|4[145]|5[1468]|6[16]|7[1467]|8[13467])[12689]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["9"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["[1-8]"],"0$1"]],"0",0,0,0,0,0,[0,["9(?:(?:0(?:[0-35]\\d|4[4-6])|(?:[13]\\d|2[0-3])\\d)\\d|9(?:[0-46]\\d\\d|5[15]0|8(?:[12]\\d|88)|9(?:0[0-3]|[19]\\d|21|69|77|8[7-9])))\\d{5}",[10]]]],IS:["354","00|1(?:0(?:01|[12]0)|100)","(?:38\\d|[4-9])\\d{6}",[7,9],[["(\\d{3})(\\d{4})","$1 $2",["[4-9]"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["3"]]],0,0,0,0,0,0,[0,["(?:38[589]\\d\\d|6(?:1[1-8]|2[0-6]|3[026-9]|4[014679]|5[0159]|6[0-69]|70|8[06-8]|9\\d)|7(?:5[057]|[6-9]\\d)|8(?:2[0-59]|[3-69]\\d|8[238]))\\d{4}"]],"00"],IT:["39","00","0\\d{5,10}|1\\d{8,10}|3(?:[0-8]\\d{7,10}|9\\d{7,8})|(?:43|55|70)\\d{8}|8\\d{5}(?:\\d{2,4})?",[6,7,8,9,10,11,12],[["(\\d{2})(\\d{4,6})","$1 $2",["0[26]"]],["(\\d{3})(\\d{3,6})","$1 $2",["0[13-57-9][0159]|8(?:03|4[17]|9[2-5])","0[13-57-9][0159]|8(?:03|4[17]|9(?:2|3[04]|[45][0-4]))"]],["(\\d{4})(\\d{2,6})","$1 $2",["0(?:[13-579][2-46-8]|8[236-8])"]],["(\\d{4})(\\d{4})","$1 $2",["894"]],["(\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3",["0[26]|5"]],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["1(?:44|[679])|[378]|43"]],["(\\d{3})(\\d{3,4})(\\d{4})","$1 $2 $3",["0[13-57-9][0159]|14"]],["(\\d{2})(\\d{4})(\\d{5})","$1 $2 $3",["0[26]"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["0"]],["(\\d{3})(\\d{4})(\\d{4,5})","$1 $2 $3",["3"]]],0,0,0,0,0,0,[0,["3[2-9]\\d{7,8}|(?:31|43)\\d{8}",[9,10]]]],JE:["44","00","1534\\d{6}|(?:[3578]\\d|90)\\d{8}",[10],0,"0",0,"([0-24-8]\\d{5})$|0","1534$1",0,0,[0,["7(?:(?:(?:50|82)9|937)\\d|7(?:00[378]|97\\d))\\d{5}"]]],JM:["1","011","(?:[58]\\d\\d|658|900)\\d{7}",[10],0,"1",0,0,0,0,"658|876",[0,["(?:658295|876(?:2(?:0[1-9]|[13-9]\\d|2[013-9])|[348]\\d\\d|5(?:0[1-9]|[1-9]\\d)|6(?:4[89]|6[67])|7(?:0[07]|7\\d|8[1-47-9]|9[0-36-9])|9(?:[01]9|9[0579])))\\d{4}"]]],JO:["962","00","(?:(?:[2689]|7\\d)\\d|32|53)\\d{6}",[8,9],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["[2356]|87"],"(0$1)"],["(\\d{3})(\\d{5,6})","$1 $2",["[89]"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["70"],"0$1"],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["7"],"0$1"]],"0",0,0,0,0,0,[0,["7(?:[78][0-25-9]|9\\d)\\d{6}",[9]]]],JP:["81","010","00[1-9]\\d{6,14}|[257-9]\\d{9}|(?:00|[1-9]\\d\\d)\\d{6}",[8,9,10,11,12,13,14,15,16,17],[["(\\d{3})(\\d{3})(\\d{3})","$1-$2-$3",["(?:12|57|99)0"],"0$1"],["(\\d{4})(\\d)(\\d{4})","$1-$2-$3",["1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|499|5(?:76|97)|746|8(?:3[89]|47|51)|9(?:80|9[16])","1(?:267|3(?:7[247]|9[278])|466|5(?:47|58|64)|6(?:3[245]|48|5[4-68]))|499[2468]|5(?:76|97)9|7468|8(?:3(?:8[7-9]|96)|477|51[2-9])|9(?:802|9(?:1[23]|69))|1(?:45|58)[67]","1(?:267|3(?:7[247]|9[278])|466|5(?:47|58|64)|6(?:3[245]|48|5[4-68]))|499[2468]|5(?:769|979[2-69])|7468|8(?:3(?:8[7-9]|96[2457-9])|477|51[2-9])|9(?:802|9(?:1[23]|69))|1(?:45|58)[67]"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3",["60"],"0$1"],["(\\d)(\\d{4})(\\d{4})","$1-$2-$3",["[36]|4(?:2[09]|7[01])","[36]|4(?:2(?:0|9[02-69])|7(?:0[019]|1))"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3",["1(?:1|5[45]|77|88|9[69])|2(?:2[1-37]|3[0-269]|4[59]|5|6[24]|7[1-358]|8[1369]|9[0-38])|4(?:[28][1-9]|3[0-57]|[45]|6[248]|7[2-579]|9[29])|5(?:2|3[0459]|4[0-369]|5[29]|8[02389]|9[0-389])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9[2-6])|8(?:2[124589]|3[26-9]|49|51|6|7[0-468]|8[68]|9[019])|9(?:[23][1-9]|4[15]|5[138]|6[1-3]|7[156]|8[189]|9[1-489])","1(?:1|5(?:4[018]|5[017])|77|88|9[69])|2(?:2(?:[127]|3[014-9])|3[0-269]|4[59]|5(?:[1-3]|5[0-69]|9[19])|62|7(?:[1-35]|8[0189])|8(?:[16]|3[0134]|9[0-5])|9(?:[028]|17))|4(?:2(?:[13-79]|8[014-6])|3[0-57]|[45]|6[248]|7[2-47]|8[1-9]|9[29])|5(?:2|3(?:[045]|9[0-8])|4[0-369]|5[29]|8[02389]|9[0-3])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9(?:[23]|4[0-59]|5[01569]|6[0167]))|8(?:2(?:[1258]|4[0-39]|9[0-2469])|3(?:[29]|60)|49|51|6(?:[0-24]|36|5[0-3589]|7[23]|9[01459])|7[0-468]|8[68])|9(?:[23][1-9]|4[15]|5[138]|6[1-3]|7[156]|8[189]|9(?:[1289]|3[34]|4[0178]))|(?:264|837)[016-9]|2(?:57|93)[015-9]|(?:25[0468]|422|838)[01]|(?:47[59]|59[89]|8(?:6[68]|9))[019]","1(?:1|5(?:4[018]|5[017])|77|88|9[69])|2(?:2[127]|3[0-269]|4[59]|5(?:[1-3]|5[0-69]|9(?:17|99))|6(?:2|4[016-9])|7(?:[1-35]|8[0189])|8(?:[16]|3[0134]|9[0-5])|9(?:[028]|17))|4(?:2(?:[13-79]|8[014-6])|3[0-57]|[45]|6[248]|7[2-47]|9[29])|5(?:2|3(?:[045]|9(?:[0-58]|6[4-9]|7[0-35689]))|4[0-369]|5[29]|8[02389]|9[0-3])|7(?:2[02-46-9]|34|[58]|6[0249]|7[57]|9(?:[23]|4[0-59]|5[01569]|6[0167]))|8(?:2(?:[1258]|4[0-39]|9[0169])|3(?:[29]|60|7(?:[017-9]|6[6-8]))|49|51|6(?:[0-24]|36[2-57-9]|5(?:[0-389]|5[23])|6(?:[01]|9[178])|7(?:2[2-468]|3[78])|9[0145])|7[0-468]|8[68])|9(?:4[15]|5[138]|7[156]|8[189]|9(?:[1289]|3(?:31|4[357])|4[0178]))|(?:8294|96)[1-3]|2(?:57|93)[015-9]|(?:223|8699)[014-9]|(?:25[0468]|422|838)[01]|(?:48|8292|9[23])[1-9]|(?:47[59]|59[89]|8(?:68|9))[019]"],"0$1"],["(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3",["[14]|[289][2-9]|5[3-9]|7[2-4679]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3",["800"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3",["[257-9]"],"0$1"]],"0",0,"(000[259]\\d{6})$|(?:(?:003768)0?)|0","$1",0,0,[0,["[7-9]0[1-9]\\d{7}",[10]]]],KE:["254","000","(?:[17]\\d\\d|900)\\d{6}|(?:2|80)0\\d{6,7}|[4-6]\\d{6,8}",[7,8,9,10],[["(\\d{2})(\\d{5,7})","$1 $2",["[24-6]"],"0$1"],["(\\d{3})(\\d{6})","$1 $2",["[17]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["[89]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:1(?:0[0-8]|1[0-7]|2[014]|30)|7\\d\\d)\\d{6}",[9]]]],KG:["996","00","8\\d{9}|[235-9]\\d{8}",[9,10],[["(\\d{4})(\\d{5})","$1 $2",["3(?:1[346]|[24-79])"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[235-79]|88"],"0$1"],["(\\d{3})(\\d{3})(\\d)(\\d{2,3})","$1 $2 $3 $4",["8"],"0$1"]],"0",0,0,0,0,0,[0,["312(?:58\\d|973)\\d{3}|(?:2(?:0[0-35]|2\\d)|5[0-24-7]\\d|600|7(?:[07]\\d|55)|88[08]|9(?:12|9[05-9]))\\d{6}",[9]]]],KH:["855","00[14-9]","1\\d{9}|[1-9]\\d{7,8}",[8,9,10],[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[1-9]"],"0$1"],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1"]]],"0",0,0,0,0,0,[0,["(?:(?:1[28]|3[18]|9[67])\\d|6[016-9]|7(?:[07-9]|[16]\\d)|8(?:[013-79]|8\\d))\\d{6}|(?:1\\d|9[0-57-9])\\d{6}|(?:2[3-6]|3[2-6]|4[2-4]|[5-7][2-5])48\\d{5}",[8,9]]]],KI:["686","00","(?:[37]\\d|6[0-79])\\d{6}|(?:[2-48]\\d|50)\\d{3}",[5,8],0,"0",0,0,0,0,0,[0,["(?:6200[01]|7(?:310[1-9]|5(?:02[03-9]|12[0-47-9]|22[0-7]|[34](?:0[1-9]|8[02-9])|50[1-9])))\\d{3}|(?:63\\d\\d|7(?:(?:[0146-9]\\d|2[0-689])\\d|3(?:[02-9]\\d|1[1-9])|5(?:[0-2][013-9]|[34][1-79]|5[1-9]|[6-9]\\d)))\\d{4}",[8]]]],KM:["269","00","[3478]\\d{6}",[7],[["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3",["[3478]"]]],0,0,0,0,0,0,[0,["[34]\\d{6}"]]],KN:["1","011","(?:[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-7]\\d{6})$|1","869$1",0,"869",[0,["869(?:48[89]|55[6-8]|66\\d|76[02-7])\\d{4}"]]],KP:["850","00|99","85\\d{6}|(?:19\\d|[2-7])\\d{7}",[8,10],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["8"],"0$1"],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["[2-7]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["1"],"0$1"]],"0",0,0,0,0,0,[0,["19[1-3]\\d{7}",[10]]]],KR:["82","00(?:[125689]|3(?:[46]5|91)|7(?:00|27|3|55|6[126]))","00[1-9]\\d{8,11}|(?:[12]|5\\d{3})\\d{7}|[13-6]\\d{9}|(?:[1-6]\\d|80)\\d{7}|[3-6]\\d{4,5}|(?:00|7)0\\d{8}",[5,6,8,9,10,11,12,13,14],[["(\\d{2})(\\d{3,4})","$1-$2",["(?:3[1-3]|[46][1-4]|5[1-5])1"],"0$1"],["(\\d{4})(\\d{4})","$1-$2",["1"]],["(\\d)(\\d{3,4})(\\d{4})","$1-$2-$3",["2"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3",["[36]0|8"],"0$1"],["(\\d{2})(\\d{3,4})(\\d{4})","$1-$2-$3",["[1346]|5[1-5]"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3",["[57]"],"0$1"],["(\\d{2})(\\d{5})(\\d{4})","$1-$2-$3",["5"],"0$1"]],"0",0,"0(8(?:[1-46-8]|5\\d\\d))?",0,0,0,[0,["1(?:05(?:[0-8]\\d|9[0-6])|22[13]\\d)\\d{4,5}|1(?:0[0-46-9]|[16-9]\\d|2[013-9])\\d{6,7}",[9,10]]]],KW:["965","00","18\\d{5}|(?:[2569]\\d|41)\\d{6}",[7,8],[["(\\d{4})(\\d{3,4})","$1 $2",["[169]|2(?:[235]|4[1-35-9])|52"]],["(\\d{3})(\\d{5})","$1 $2",["[245]"]]],0,0,0,0,0,0,[0,["(?:41\\d\\d|5(?:(?:[05]\\d|1[0-7]|6[56])\\d|2(?:22|5[25])|7(?:55|77)|88[58])|6(?:(?:0[034679]|5[015-9]|6\\d)\\d|1(?:00|11|6[16])|2[26]2|3[36]3|4[46]4|7(?:0[013-9]|[67]\\d)|8[68]8|9(?:[069]\\d|3[039]))|9(?:(?:[04679]\\d|8[057-9])\\d|1(?:1[01]|99)|2(?:00|2\\d)|3(?:00|3[03])|5(?:00|5\\d)))\\d{4}",[8]]]],KY:["1","011","(?:345|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","345$1",0,"345",[0,["345(?:32[1-9]|42[0-4]|5(?:1[67]|2[5-79]|4[6-9]|50|76)|649|82[56]|9(?:1[679]|2[2-9]|3[06-9]|90))\\d{4}"]]],KZ:["7","810","(?:33622|8\\d{8})\\d{5}|[78]\\d{9}",[10,14],0,"8",0,0,0,0,"33|7",[0,["7(?:0[0-25-8]|47|6[0-4]|7[15-8]|85)\\d{7}",[10]]],"8~10"],LA:["856","00","[23]\\d{9}|3\\d{8}|(?:[235-8]\\d|41)\\d{6}",[8,9,10],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["2[13]|3[14]|[4-8]"],"0$1"],["(\\d{2})(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3 $4",["30[0135-9]"],"0$1"],["(\\d{2})(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3 $4",["[23]"],"0$1"]],"0",0,0,0,0,0,[0,["208[78]\\d{6}|(?:20[23579]|30[24])\\d{7}",[10]]]],LB:["961","00","[27-9]\\d{7}|[13-9]\\d{6}",[7,8],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["[13-69]|7(?:[2-57]|62|8[0-7]|9[04-9])|8[02-9]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[27-9]"]]],"0",0,0,0,0,0,[0,["793(?:[01]\\d|2[0-4])\\d{3}|(?:(?:3|81)\\d|7(?:[01]\\d|6[013-9]|8[89]|9[12]))\\d{5}"]]],LC:["1","011","(?:[58]\\d\\d|758|900)\\d{7}",[10],0,"1",0,"([2-8]\\d{6})$|1","758$1",0,"758",[0,["758(?:28[4-7]|384|4(?:6[01]|8[4-9])|5(?:1[89]|20|84)|7(?:1[2-9]|2\\d|3[0-3])|812)\\d{4}"]]],LI:["423","00","[68]\\d{8}|(?:[2378]\\d|90)\\d{5}",[7,9],[["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3",["[2379]|8(?:0[09]|7)","[2379]|8(?:0(?:02|9)|7)"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["8"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["69"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["6"]]],"0",0,"(1001)|0",0,0,0,[0,["(?:6(?:(?:4[5-9]|5[0-469])\\d|6(?:[024-6]\\d|[17]0|3[7-9]))\\d|7(?:[37-9]\\d|42|56))\\d{4}"]]],LK:["94","00","[1-9]\\d{8}",[9],[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["7"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[1-689]"],"0$1"]],"0",0,0,0,0,0,[0,["7(?:[0-25-8]\\d|4[0-4])\\d{6}"]]],LR:["231","00","(?:[245]\\d|33|77|88)\\d{7}|(?:2\\d|[4-6])\\d{6}",[7,8,9],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["4[67]|[56]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["2"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[2-578]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:(?:(?:22|33)0|555|(?:77|88)\\d)\\d|4(?:240|[67]))\\d{5}|[56]\\d{6}",[7,9]]]],LS:["266","00","(?:[256]\\d\\d|800)\\d{5}",[8],[["(\\d{4})(\\d{4})","$1 $2",["[2568]"]]],0,0,0,0,0,0,[0,["[56]\\d{7}"]]],LT:["370","00","(?:[3469]\\d|52|[78]0)\\d{6}",[8],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["52[0-7]"],"(0-$1)",1],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["[7-9]"],"0 $1",1],["(\\d{2})(\\d{6})","$1 $2",["37|4(?:[15]|6[1-8])"],"(0-$1)",1],["(\\d{3})(\\d{5})","$1 $2",["[3-6]"],"(0-$1)",1]],"0",0,"[08]",0,0,0,[0,["6\\d{7}"]]],LU:["352","00","35[013-9]\\d{4,8}|6\\d{8}|35\\d{2,4}|(?:[2457-9]\\d|3[0-46-9])\\d{2,9}",[4,5,6,7,8,9,10,11],[["(\\d{2})(\\d{3})","$1 $2",["2(?:0[2-689]|[2-9])|[3-57]|8(?:0[2-9]|[13-9])|9(?:0[89]|[2-579])"]],["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",["2(?:0[2-689]|[2-9])|[3-57]|8(?:0[2-9]|[13-9])|9(?:0[89]|[2-579])"]],["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3",["20[2-689]"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})","$1 $2 $3 $4",["2(?:[0367]|4[3-8])"]],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["80[01]|90[015]"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3 $4",["20"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["6"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})","$1 $2 $3 $4 $5",["2(?:[0367]|4[3-8])"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{1,5})","$1 $2 $3 $4",["[3-57]|8[13-9]|9(?:0[89]|[2-579])|(?:2|80)[2-9]"]]],0,0,"(15(?:0[06]|1[12]|[35]5|4[04]|6[26]|77|88|99)\\d)",0,0,0,[0,["6(?:[269][18]|5[1568]|7[189]|81)\\d{6}",[9]]]],LV:["371","00","(?:[268]\\d|90)\\d{6}",[8],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[269]|8[01]"]]],0,0,0,0,0,0,[0,["2333[0-8]\\d{3}|2(?:[0-24-9]\\d\\d|3(?:0[07]|[14-9]\\d|2[02-9]|3[0-24-9]))\\d{4}"]]],LY:["218","00","[2-9]\\d{8}",[9],[["(\\d{2})(\\d{7})","$1-$2",["[2-9]"],"0$1"]],"0",0,0,0,0,0,[0,["9[1-6]\\d{7}"]]],MA:["212","00","[5-8]\\d{8}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["5[45]"],"0$1"],["(\\d{4})(\\d{5})","$1-$2",["5(?:2[2-46-9]|3[3-9]|9)|8(?:0[89]|92)"],"0$1"],["(\\d{2})(\\d{7})","$1-$2",["8"],"0$1"],["(\\d{3})(\\d{6})","$1-$2",["[5-7]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:6(?:[0-79]\\d|8[0-247-9])|7(?:[0167]\\d|2[0-467]|5[0-3]|8[0-5]))\\d{6}"]]],MC:["377","00","(?:[3489]|6\\d)\\d{7}",[8,9],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["4"],"0$1"],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[389]"]],["(\\d)(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5",["6"],"0$1"]],"0",0,0,0,0,0,[0,["4(?:[469]\\d|5[1-9])\\d{5}|(?:3|6\\d)\\d{7}"]]],MD:["373","00","(?:[235-7]\\d|[89]0)\\d{6}",[8],[["(\\d{3})(\\d{5})","$1 $2",["[89]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["22|3"],"0$1"],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["[25-7]"],"0$1"]],"0",0,0,0,0,0,[0,["562\\d{5}|(?:6\\d|7[16-9])\\d{6}"]]],ME:["382","00","(?:20|[3-79]\\d)\\d{6}|80\\d{6,7}",[8,9],[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[2-9]"],"0$1"]],"0",0,0,0,0,0,[0,["6(?:[07-9]\\d|3[024]|6[0-25])\\d{5}",[8]]]],MF:["590","00","(?:590\\d|7090)\\d{5}|(?:69|80|9\\d)\\d{7}",[9],0,"0",0,0,0,0,0,[0,["(?:69(?:0\\d\\d|1(?:2[2-9]|3[0-5])|4(?:0[89]|1[2-6]|9\\d)|6(?:1[016-9]|5[0-4]|[67]\\d))|7090[0-4])\\d{4}"]]],MG:["261","00","[23]\\d{8}",[9],[["(\\d{2})(\\d{2})(\\d{3})(\\d{2})","$1 $2 $3 $4",["[23]"],"0$1"]],"0",0,"([24-9]\\d{6})$|0","20$1",0,0,[0,["3[2-47-9]\\d{7}"]]],MH:["692","011","329\\d{4}|(?:[256]\\d|45)\\d{5}",[7],[["(\\d{3})(\\d{4})","$1-$2",["[2-6]"]]],"1",0,0,0,0,0,[0,["(?:(?:23|54)5|329|45[35-8])\\d{4}"]]],MK:["389","00","[2-578]\\d{7}",[8],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["2|34[47]|4(?:[37]7|5[47]|64)"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[347]"],"0$1"],["(\\d{3})(\\d)(\\d{2})(\\d{2})","$1 $2 $3 $4",["[58]"],"0$1"]],"0",0,0,0,0,0,[0,["7(?:3555|(?:474|9[019]7)7)\\d{3}|7(?:[0-25-8]\\d\\d|3(?:[1-478]\\d|6[01])|4(?:2\\d|60|7[01578])|9(?:[2-4]\\d|5[01]|7[015]))\\d{4}"]]],ML:["223","00","[24-9]\\d{7}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[24-9]"]]],0,0,0,0,0,0,[0,["2(?:0(?:01|79)|17\\d)\\d{4}|(?:5[01]|[679]\\d|8[2-59])\\d{6}"]]],MM:["95","00","1\\d{5,7}|95\\d{6}|(?:[4-7]|9[0-46-9])\\d{6,8}|(?:2|8\\d)\\d{5,8}",[6,7,8,9,10],[["(\\d)(\\d{2})(\\d{3})","$1 $2 $3",["16|2"],"0$1"],["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3",["4(?:[2-46]|5[3-5])|5|6(?:[1-689]|7[235-7])|7(?:[0-4]|5[2-7])|8[1-5]|(?:60|86)[23]"],"0$1"],["(\\d)(\\d{3})(\\d{3,4})","$1 $2 $3",["[12]|452|678|86","[12]|452|6788|86"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[4-7]|8[1-35]"],"0$1"],["(\\d)(\\d{3})(\\d{4,6})","$1 $2 $3",["9(?:2[0-4]|[35-9]|4[137-9])"],"0$1"],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["2"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8"],"0$1"],["(\\d)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["92"],"0$1"],["(\\d)(\\d{5})(\\d{4})","$1 $2 $3",["9"],"0$1"]],"0",0,0,0,0,0,[0,["(?:17[01]|9(?:2(?:[0-4]|[56]\\d\\d)|(?:3(?:[0-36]|4\\d)|(?:6\\d|8[89]|9[4-8])\\d|7(?:3|40|[5-9]\\d))\\d|4(?:(?:[0245]\\d|[1379])\\d|88)|5[0-6])\\d)\\d{4}|9[69]1\\d{6}|9(?:[68]\\d|9[089])\\d{5}",[7,8,9,10]]]],MN:["976","001","[12]\\d{7,9}|[5-9]\\d{7}",[8,9,10],[["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",["[12]1"],"0$1"],["(\\d{4})(\\d{4})","$1 $2",["[5-9]"]],["(\\d{3})(\\d{5,6})","$1 $2",["[12]2[1-3]"],"0$1"],["(\\d{4})(\\d{5,6})","$1 $2",["[12](?:27|3[2-8]|4[2-68]|5[1-4689])","[12](?:27|3[2-8]|4[2-68]|5[1-4689])[0-3]"],"0$1"],["(\\d{5})(\\d{4,5})","$1 $2",["[12]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:83[01]|92[039])\\d{5}|(?:5[05]|6[069]|72|8[015689]|9[013-9])\\d{6}",[8]]]],MO:["853","00","0800\\d{3}|(?:28|[68]\\d)\\d{6}",[7,8],[["(\\d{4})(\\d{3})","$1 $2",["0"]],["(\\d{4})(\\d{4})","$1 $2",["[268]"]]],0,0,0,0,0,0,[0,["6800[0-79]\\d{3}|6(?:[235]\\d\\d|6(?:0[0-5]|[1-9]\\d)|8(?:0[1-9]|[14-8]\\d|2[5-9]|[39][0-4]))\\d{4}",[8]]]],MP:["1","011","[58]\\d{9}|(?:67|90)0\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","670$1",0,"670",[0,["670(?:2(?:3[3-7]|56|8[4-8])|32[1-38]|4(?:33|8[348])|5(?:32|55|88)|6(?:64|70|82)|78[3589]|8[3-9]8|989)\\d{4}"]]],MQ:["596","00","(?:596\\d|7091)\\d{5}|(?:69|[89]\\d)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-79]|8(?:0[6-9]|[36])"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:69[67]\\d\\d|7091[0-3])\\d{4}"]]],MR:["222","00","(?:[2-4]\\d\\d|800)\\d{5}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2-48]"]]],0,0,0,0,0,0,[0,["[2-4][0-46-9]\\d{6}"]]],MS:["1","011","(?:[58]\\d\\d|664|900)\\d{7}",[10],0,"1",0,"([34]\\d{6})$|1","664$1",0,"664",[0,["664(?:3(?:49|9[1-6])|49[2-6])\\d{4}"]]],MT:["356","00","3550\\d{4}|(?:[2579]\\d\\d|800)\\d{5}",[8],[["(\\d{4})(\\d{4})","$1 $2",["[2357-9]"]]],0,0,0,0,0,0,[0,["(?:7(?:210|[79]\\d\\d)|9(?:[29]\\d\\d|69[67]|8(?:1[1-3]|89|97)))\\d{4}"]]],MU:["230","0(?:0|[24-7]0|3[03])","(?:[57]|8\\d\\d)\\d{7}|[2-468]\\d{6}",[7,8,10],[["(\\d{3})(\\d{4})","$1 $2",["[2-46]|8[013]"]],["(\\d{4})(\\d{4})","$1 $2",["[57]"]],["(\\d{5})(\\d{5})","$1 $2",["8"]]],0,0,0,0,0,0,[0,["5(?:4(?:2[1-389]|7[1-9])|87[15-8])\\d{4}|(?:5(?:2[5-9]|4[3-689]|[57]\\d|8[0-689]|9[0-8])|7(?:0[0-4]|3[013]))\\d{5}",[8]]],"020"],MV:["960","0(?:0|19)","(?:800|9[0-57-9]\\d)\\d{7}|[34679]\\d{6}",[7,10],[["(\\d{3})(\\d{4})","$1-$2",["[34679]"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[89]"]]],0,0,0,0,0,0,[0,["(?:46[46]|[79]\\d\\d)\\d{4}",[7]]],"00"],MW:["265","00","(?:[1289]\\d|31|77)\\d{7}|1\\d{6}",[7,9],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["1[2-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["2"],"0$1"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[137-9]"],"0$1"]],"0",0,0,0,0,0,[0,["111\\d{6}|(?:31|77|[89][89])\\d{7}",[9]]]],MX:["52","0[09]","[2-9]\\d{9}",[10],[["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["33|5[56]|81"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[2-9]"]]],0,0,0,0,0,0,[0,["657[12]\\d{6}|(?:2(?:2\\d|3[1-35-8]|4[13-9]|7[1-689]|8[1-578]|9[467])|3(?:1[1-79]|[2458][1-9]|3\\d|7[1-8]|9[1-5])|4(?:1[1-57-9]|[267][1-9]|3[1-8]|[45]\\d|8[1-35-9]|9[2-689])|5(?:[56]\\d|88|9[1-79])|6(?:1[2-68]|[2-4][1-9]|5[1-3689]|6[0-57-9]|7[1-7]|8[67]|9[4-8])|7(?:[1346][1-9]|[27]\\d|5[13-9]|8[1-69]|9[17])|8(?:1\\d|2[13-689]|3[1-6]|4[124-6]|6[1246-9]|7[0-378]|9[12479])|9(?:1[346-9]|2[1-4]|3[2-46-8]|5[1348]|[69]\\d|7[12]|8[1-8]))\\d{7}"]],"00"],MY:["60","00","1\\d{8,9}|(?:3\\d|[4-9])\\d{7}",[8,9,10],[["(\\d)(\\d{3})(\\d{4})","$1-$2 $3",["[4-79]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1-$2 $3",["1(?:[02469]|[378][1-9]|53)|8","1(?:[02469]|[37][1-9]|53|8(?:[1-46-9]|5[7-9]))|8"],"0$1"],["(\\d)(\\d{4})(\\d{4})","$1-$2 $3",["3"],"0$1"],["(\\d)(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3-$4",["1(?:[367]|80)"]],["(\\d{3})(\\d{3})(\\d{4})","$1-$2 $3",["15"],"0$1"],["(\\d{2})(\\d{4})(\\d{4})","$1-$2 $3",["1"],"0$1"]],"0",0,0,0,0,0,[0,["1(?:1888[689]|4400|8(?:47|8[27])[0-4])\\d{4}|1(?:0(?:[23568]\\d|4[0-6]|7[016-9]|9[0-8])|1(?:[1-5]\\d\\d|6(?:0[5-9]|[1-9]\\d)|7(?:[0-4]\\d|5[0-7]))|(?:[269]\\d|[37][1-9]|4[235-9])\\d|5(?:31|9\\d\\d)|8(?:1[23]|[236]\\d|4[06]|5(?:46|[7-9])|7[016-9]|8[01]|9[0-8]))\\d{5}",[9,10]]]],MZ:["258","00","(?:2|8\\d)\\d{7}",[8,9],[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["2|8[2-79]"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["8[2-79]\\d{7}",[9]]]],NA:["264","00","[68]\\d{7,8}",[8,9],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["88"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["6"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["87"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:60|8[1245])\\d{7}",[9]]]],NC:["687","00","(?:050|[2-57-9]\\d\\d)\\d{3}",[6],[["(\\d{2})(\\d{2})(\\d{2})","$1.$2.$3",["[02-57-9]"]]],0,0,0,0,0,0,[0,["(?:[579]\\d|8[0-79])\\d{4}"]]],NE:["227","00","[027-9]\\d{7}",[8],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["08"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[089]|2[013]|7[0467]"]]],0,0,0,0,0,0,[0,["(?:23|7[0467]|[89]\\d)\\d{6}"]]],NF:["672","00","[13]\\d{5}",[6],[["(\\d{2})(\\d{4})","$1 $2",["1[0-3]"]],["(\\d)(\\d{5})","$1 $2",["[13]"]]],0,0,"([0-258]\\d{4})$","3$1",0,0,[0,["(?:14|3[58])\\d{4}"]]],NG:["234","009","38\\d{6}|[78]\\d{9,13}|(?:20|9\\d)\\d{8}",[8,10,11,12,13,14],[["(\\d{2})(\\d{3})(\\d{2,3})","$1 $2 $3",["3"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["[7-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["20[129]"],"0$1"],["(\\d{4})(\\d{2})(\\d{4})","$1 $2 $3",["2"],"0$1"],["(\\d{3})(\\d{4})(\\d{4,5})","$1 $2 $3",["[78]"],"0$1"],["(\\d{3})(\\d{5})(\\d{5,6})","$1 $2 $3",["[78]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:702[0-24-9]|819[01])\\d{6}|(?:7(?:0[13-9]|[12]\\d)|8(?:0[1-9]|1[0-8])|9(?:0[1-9]|1[1-6]))\\d{7}",[10]]]],NI:["505","00","(?:1800|[25-8]\\d{3})\\d{4}",[8],[["(\\d{4})(\\d{4})","$1 $2",["[125-8]"]]],0,0,0,0,0,0,[0,["(?:5(?:5[0-7]|[78]\\d)|6(?:20|3[035]|4[045]|5[05]|77|8[1-9]|9[059])|(?:7[5-8]|8\\d)\\d)\\d{5}"]]],NL:["31","00","(?:[124-7]\\d\\d|3(?:[02-9]\\d|1[0-8]))\\d{6}|8\\d{6,9}|9\\d{6,10}|1\\d{4,5}",[5,6,7,8,9,10,11],[["(\\d{3})(\\d{4,7})","$1 $2",["[89]0"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["66"],"0$1"],["(\\d)(\\d{8})","$1 $2",["6"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["1[16-8]|2[259]|3[124]|4[17-9]|5[124679]"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[1-578]|91"],"0$1"],["(\\d{3})(\\d{3})(\\d{5})","$1 $2 $3",["9"],"0$1"]],"0",0,0,0,0,0,[0,["(?:6[1-58]|970\\d)\\d{7}",[9,11]]]],NO:["47","00","(?:0|[2-9]\\d{3})\\d{4}",[5,8],[["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3",["8"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[2-79]"]]],0,0,0,0,0,"[02-689]|7[0-8]",[0,["(?:4[015-8]|9\\d)\\d{6}",[8]]]],NP:["977","00","(?:1\\d|9)\\d{9}|[1-9]\\d{7}",[8,10,11],[["(\\d)(\\d{7})","$1-$2",["1[2-6]"],"0$1"],["(\\d{2})(\\d{6})","$1-$2",["1[01]|[2-8]|9(?:[1-59]|[67][2-6])"],"0$1"],["(\\d{3})(\\d{7})","$1-$2",["9"]]],"0",0,0,0,0,0,[0,["9(?:00|6[0-3]|7[024-6]|8[0-24-68])\\d{7}",[10]]]],NR:["674","00","(?:444|(?:55|8\\d)\\d|666)\\d{4}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[4-68]"]]],0,0,0,0,0,0,[0,["(?:55[3-9]|666|8\\d\\d)\\d{4}"]]],NU:["683","00","(?:[4-7]|888\\d)\\d{3}",[4,7],[["(\\d{3})(\\d{4})","$1 $2",["8"]]],0,0,0,0,0,0,[0,["(?:[56]|888[1-9])\\d{3}"]]],NZ:["64","0(?:0|161)","[1289]\\d{9}|50\\d{5}(?:\\d{2,3})?|[27-9]\\d{7,8}|(?:[34]\\d|6[0-35-9])\\d{6}|8\\d{4,6}",[5,6,7,8,9,10],[["(\\d{2})(\\d{3,8})","$1 $2",["8[1-79]"],"0$1"],["(\\d{3})(\\d{2})(\\d{2,3})","$1 $2 $3",["50[036-8]|8|90","50(?:[0367]|88)|8|90"],"0$1"],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["24|[346]|7[2-57-9]|9[2-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["2(?:10|74)|[589]"],"0$1"],["(\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3",["1|2[028]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,5})","$1 $2 $3",["2(?:[169]|7[0-35-9])|7"],"0$1"]],"0",0,0,0,0,0,[0,["2(?:[0-27-9]\\d|6)\\d{6,7}|2(?:1\\d|75)\\d{5}",[8,9,10]]],"00"],OM:["968","00","(?:1505|[279]\\d{3}|500)\\d{4}|800\\d{5,6}",[7,8,9],[["(\\d{3})(\\d{4,6})","$1 $2",["[58]"]],["(\\d{2})(\\d{6})","$1 $2",["2"]],["(\\d{4})(\\d{4})","$1 $2",["[179]"]]],0,0,0,0,0,0,[0,["(?:1505|90[1-9]\\d)\\d{4}|(?:7[126-9]|9[1-9])\\d{6}",[8]]]],PA:["507","00","(?:00800|8\\d{3})\\d{6}|[68]\\d{7}|[1-57-9]\\d{6}",[7,8,10,11],[["(\\d{3})(\\d{4})","$1-$2",["[1-57-9]"]],["(\\d{4})(\\d{4})","$1-$2",["[68]"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["(?:1[16]1|21[89]|6\\d{3}|8(?:1[01]|7[23]))\\d{4}",[7,8]]]],PE:["51","00|19(?:1[124]|77|90)00","(?:[14-8]|9\\d)\\d{7}",[8,9],[["(\\d{3})(\\d{5})","$1 $2",["80"],"(0$1)"],["(\\d)(\\d{7})","$1 $2",["1"],"(0$1)"],["(\\d{2})(\\d{6})","$1 $2",["[4-8]"],"(0$1)"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["9"]]],"0",0,0,0,0,0,[0,["9\\d{8}",[9]]],"00"," Anexo "],PF:["689","00","4\\d{5}(?:\\d{2})?|8\\d{7,8}",[6,8,9],[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",["44"]],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["4|8[7-9]"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"]]],0,0,0,0,0,0,[0,["8[7-9]\\d{6}",[8]]]],PG:["675","00|140[1-3]","(?:180|[78]\\d{3})\\d{4}|(?:[2-589]\\d|64)\\d{5}",[7,8],[["(\\d{3})(\\d{4})","$1 $2",["18|[2-69]|85"]],["(\\d{4})(\\d{4})","$1 $2",["[78]"]]],0,0,0,0,0,0,[0,["(?:7\\d|8[1-38])\\d{6}",[8]]],"00"],PH:["63","00","(?:[2-7]|9\\d)\\d{8}|2\\d{5}|(?:1800|8)\\d{7,9}",[6,8,9,10,11,12,13],[["(\\d)(\\d{5})","$1 $2",["2"],"(0$1)"],["(\\d{4})(\\d{4,6})","$1 $2",["3(?:23|39|46)|4(?:2[3-6]|[35]9|4[26]|76)|544|88[245]|(?:52|64|86)2","3(?:230|397|461)|4(?:2(?:35|[46]4|51)|396|4(?:22|63)|59[347]|76[15])|5(?:221|446)|642[23]|8(?:622|8(?:[24]2|5[13]))"],"(0$1)"],["(\\d{5})(\\d{4})","$1 $2",["346|4(?:27|9[35])|883","3469|4(?:279|9(?:30|56))|8834"],"(0$1)"],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["2"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[3-7]|8[2-8]"],"(0$1)"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["[89]"],"0$1"],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["1"]],["(\\d{4})(\\d{1,2})(\\d{3})(\\d{4})","$1 $2 $3 $4",["1"]]],"0",0,0,0,0,0,[0,["(?:8(?:1[37]|9[5-8])|9(?:0[5-9]|1[0-24-9]|[235-7]\\d|4[2-9]|8[135-9]|9[1-9]))\\d{7}",[10]]]],PK:["92","00","122\\d{6}|[24-8]\\d{10,11}|9(?:[013-9]\\d{8,10}|2(?:[01]\\d\\d|2(?:[06-8]\\d|1[01]))\\d{7})|(?:[2-8]\\d{3}|92(?:[0-7]\\d|8[1-9]))\\d{6}|[24-9]\\d{8}|[89]\\d{7}",[8,9,10,11,12],[["(\\d{3})(\\d{3})(\\d{2,7})","$1 $2 $3",["[89]0"],"0$1"],["(\\d{4})(\\d{5})","$1 $2",["1"]],["(\\d{3})(\\d{6,7})","$1 $2",["2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:2[2-8]|3[27-9]|4[2-6]|6[3569]|9[25-8])","9(?:2[3-8]|98)|(?:2(?:3[2358]|4[2-4]|9[2-8])|45[3479]|54[2-467]|60[468]|72[236]|8(?:2[2-689]|3[23578]|4[3478]|5[2356])|9(?:22|3[27-9]|4[2-6]|6[3569]|9[25-7]))[2-9]"],"(0$1)"],["(\\d{2})(\\d{7,8})","$1 $2",["(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]"],"(0$1)"],["(\\d{5})(\\d{5})","$1 $2",["58"],"(0$1)"],["(\\d{3})(\\d{7})","$1 $2",["3"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91"],"(0$1)"],["(\\d{3})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["[24-9]"],"(0$1)"]],"0",0,0,0,0,0,[0,["3(?:[0-247]\\d|3[0-79]|55|64)\\d{7}",[10]]]],PL:["48","00","(?:6|8\\d\\d)\\d{7}|[1-9]\\d{6}(?:\\d{2})?|[26]\\d{5}",[6,7,8,9,10],[["(\\d{5})","$1",["19"]],["(\\d{3})(\\d{3})","$1 $2",["11|20|64"]],["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3",["(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])1","(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])19"]],["(\\d{3})(\\d{2})(\\d{2,3})","$1 $2 $3",["64"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["21|39|45|5[0137]|6[0469]|7[02389]|8(?:0[14]|8)"]],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["1[2-8]|[2-7]|8[1-79]|9[145]"]],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["8"]]],0,0,0,0,0,0,[0,["2131[89]\\d{4}|21(?:1[013-5]|2\\d|3[2-9])\\d{5}|(?:45|5[0137]|6[069]|7[2389]|88)\\d{7}",[9]]]],PM:["508","00","[45]\\d{5}|(?:708|8\\d\\d)\\d{6}",[6,9],[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",["[45]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["7"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:4[02-489]|5[02-9]|708(?:4[0-5]|5[0-6]))\\d{4}"]]],PR:["1","011","(?:[589]\\d\\d|787)\\d{7}",[10],0,"1",0,0,0,0,"787|939",[0,["(?:787|939)[2-9]\\d{6}"]]],PS:["970","00","[2489]2\\d{6}|(?:1\\d|5)\\d{8}",[8,9,10],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["[2489]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["5"],"0$1"],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1"]]],"0",0,0,0,0,0,[0,["5[69]\\d{7}",[9]]]],PT:["351","00","1693\\d{5}|(?:[26-9]\\d|30)\\d{7}",[9],[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["2[12]"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["16|[236-9]"]]],0,0,0,0,0,0,[0,["6(?:[06]92(?:30|9\\d)|[35]92(?:[049]\\d|3[034]))\\d{3}|(?:(?:16|6[0356])93|9(?:[1-36]\\d\\d|480))\\d{5}"]]],PW:["680","01[12]","(?:[24-8]\\d\\d|345|900)\\d{4}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[2-9]"]]],0,0,0,0,0,0,[0,["(?:(?:46|83)[0-5]|(?:6[2-4689]|78)0)\\d{4}|(?:45|77|88)\\d{5}"]]],PY:["595","00","59\\d{4,6}|9\\d{5,10}|(?:[2-46-8]\\d|5[0-8])\\d{4,7}",[6,7,8,9,10,11],[["(\\d{3})(\\d{3,6})","$1 $2",["[2-9]0"],"0$1"],["(\\d{2})(\\d{5})","$1 $2",["[26]1|3[289]|4[1246-8]|7[1-3]|8[1-36]"],"(0$1)"],["(\\d{3})(\\d{4,5})","$1 $2",["2[279]|3[13-5]|4[359]|5|6(?:[34]|7[1-46-8])|7[46-8]|85"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["2[14-68]|3[26-9]|4[1246-8]|6(?:1|75)|7[1-35]|8[1-36]"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["87"]],["(\\d{3})(\\d{6})","$1 $2",["9(?:[5-79]|8[1-7])"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[2-8]"],"0$1"],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["9"]]],"0",0,0,0,0,0,[0,["9(?:51|6[129]|7[1-6]|8[1-7]|9[1-5])\\d{6}",[9]]]],QA:["974","00","800\\d{4}|(?:2|800)\\d{6}|(?:0080|[3-7])\\d{7}",[7,8,9,11],[["(\\d{3})(\\d{4})","$1 $2",["2[16]|8"]],["(\\d{4})(\\d{4})","$1 $2",["[3-7]"]]],0,0,0,0,0,0,[0,["[35-7]\\d{7}",[8]]]],RE:["262","00","709\\d{6}|(?:26|[689]\\d)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[26-9]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:69(?:2\\d\\d|3(?:[06][0-6]|1[013]|2[0-2]|3[0-39]|4\\d|5[0-5]|7[0-37]|8[0-8]|9[0-479]))|7092[0-3])\\d{4}"]]],RO:["40","00","(?:[236-8]\\d|90)\\d{7}|[23]\\d{5}",[6,9],[["(\\d{3})(\\d{3})","$1 $2",["2[3-6]","2[3-6]\\d9"],"0$1"],["(\\d{2})(\\d{4})","$1 $2",["219|31"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[23]1"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[236-9]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:630|702)0\\d{5}|(?:6(?:00|2\\d)|7(?:0[013-9]|1[0-3]|[2-7]\\d|8[03-8]|9[0-39]))\\d{6}",[9]]],0," int "],RS:["381","00","38[02-9]\\d{6,9}|6\\d{7,9}|90\\d{4,8}|38\\d{5,6}|(?:7\\d\\d|800)\\d{3,9}|(?:[12]\\d|3[0-79])\\d{5,10}",[6,7,8,9,10,11,12],[["(\\d{3})(\\d{3,9})","$1 $2",["(?:2[389]|39)0|[7-9]"],"0$1"],["(\\d{2})(\\d{5,10})","$1 $2",["[1-36]"],"0$1"]],"0",0,0,0,0,0,[0,["6(?:[0-689]|7\\d)\\d{6,7}",[8,9,10]]]],RU:["7","810","8\\d{13}|[347-9]\\d{9}",[10,14],[["(\\d{4})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["7(?:1[0-8]|2[1-9])","7(?:1(?:[0-356]2|4[29]|7|8[27])|2(?:1[23]|[2-9]2))","7(?:1(?:[0-356]2|4[29]|7|8[27])|2(?:13[03-69]|62[013-9]))|72[1-57-9]2"],"8 ($1)",1],["(\\d{5})(\\d)(\\d{2})(\\d{2})","$1 $2 $3 $4",["7(?:1[0-68]|2[1-9])","7(?:1(?:[06][3-6]|[18]|2[35]|[3-5][3-5])|2(?:[13][3-5]|[24-689]|7[457]))","7(?:1(?:0(?:[356]|4[023])|[18]|2(?:3[013-9]|5)|3[45]|43[013-79]|5(?:3[1-8]|4[1-7]|5)|6(?:3[0-35-9]|[4-6]))|2(?:1(?:3[178]|[45])|[24-689]|3[35]|7[457]))|7(?:14|23)4[0-8]|71(?:33|45)[1-79]"],"8 ($1)",1],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["7"],"8 ($1)",1],["(\\d{3})(\\d{3})(\\d{2})(\\d{2})","$1 $2-$3-$4",["[349]|8(?:[02-7]|1[1-8])"],"8 ($1)",1],["(\\d{4})(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3 $4",["8"],"8 ($1)"]],"8",0,0,0,0,"3[04-689]|[489]",[0,["9\\d{9}",[10]]],"8~10"],RW:["250","00","(?:06|[27]\\d\\d|[89]00)\\d{6}",[8,9],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["0"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["2"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[7-9]"],"0$1"]],"0",0,0,0,0,0,[0,["7[237-9]\\d{7}",[9]]]],SA:["966","00","92\\d{7}|(?:[15]|8\\d)\\d{8}",[9,10],[["(\\d{4})(\\d{5})","$1 $2",["9"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["1"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["5"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["81"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8"]]],"0",0,0,0,0,0,[0,["579[01]\\d{5}|5(?:[013-689]\\d|7[0-8])\\d{6}",[9]]]],SB:["677","0[01]","[6-9]\\d{6}|[1-6]\\d{4}",[5,7],[["(\\d{2})(\\d{5})","$1 $2",["6[89]|7|8[4-9]|9(?:[1-8]|9[0-8])"]]],0,0,0,0,0,0,[0,["48\\d{3}|(?:(?:6[89]|7[1-9]|8[4-9])\\d|9(?:1[2-9]|2[013-9]|3[0-2]|[46]\\d|5[0-46-9]|7[0-689]|8[0-79]|9[0-8]))\\d{4}"]]],SC:["248","010|0[0-2]","(?:[2489]\\d|64)\\d{5}",[7],[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",["[246]|9[57]"]]],0,0,0,0,0,0,[0,["2[125-8]\\d{5}"]],"00"],SD:["249","00","[19]\\d{8}",[9],[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[19]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:1[0-2]|9[0-3569])\\d{7}"]]],SE:["46","00","(?:[26]\\d\\d|9)\\d{9}|[1-9]\\d{8}|[1-689]\\d{7}|[1-4689]\\d{6}|2\\d{5}",[6,7,8,9,10,12],[["(\\d{2})(\\d{2,3})(\\d{2})","$1-$2 $3",["20"],"0$1",0,"$1 $2 $3"],["(\\d{3})(\\d{4})","$1-$2",["9(?:00|39|44|9)"],"0$1",0,"$1 $2"],["(\\d{2})(\\d{3})(\\d{2})","$1-$2 $3",["[12][136]|3[356]|4[0246]|6[03]|90[1-9]"],"0$1",0,"$1 $2 $3"],["(\\d)(\\d{2,3})(\\d{2})(\\d{2})","$1-$2 $3 $4",["8"],"0$1",0,"$1 $2 $3 $4"],["(\\d{3})(\\d{2,3})(\\d{2})","$1-$2 $3",["1[2457]|2(?:[247-9]|5[0138])|3[0247-9]|4[1357-9]|5[0-35-9]|6(?:[125689]|4[02-57]|7[0-2])|9(?:[125-8]|3[02-5]|4[0-3])"],"0$1",0,"$1 $2 $3"],["(\\d{3})(\\d{2,3})(\\d{3})","$1-$2 $3",["9(?:00|39|44)"],"0$1",0,"$1 $2 $3"],["(\\d{2})(\\d{2,3})(\\d{2})(\\d{2})","$1-$2 $3 $4",["1[13689]|2[0136]|3[1356]|4[0246]|54|6[03]|90[1-9]"],"0$1",0,"$1 $2 $3 $4"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1-$2 $3 $4",["10|7"],"0$1",0,"$1 $2 $3 $4"],["(\\d)(\\d{3})(\\d{3})(\\d{2})","$1-$2 $3 $4",["8"],"0$1",0,"$1 $2 $3 $4"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1-$2 $3 $4",["[13-5]|2(?:[247-9]|5[0138])|6(?:[124-689]|7[0-2])|9(?:[125-8]|3[02-5]|4[0-3])"],"0$1",0,"$1 $2 $3 $4"],["(\\d{3})(\\d{2})(\\d{2})(\\d{3})","$1-$2 $3 $4",["9"],"0$1",0,"$1 $2 $3 $4"],["(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1-$2 $3 $4 $5",["[26]"],"0$1",0,"$1 $2 $3 $4 $5"]],"0",0,0,0,0,0,[0,["7[02369]\\d{7}",[9]]]],SG:["65","0[0-3]\\d","(?:(?:1\\d|8)\\d\\d|7000)\\d{7}|[3689]\\d{7}",[8,10,11],[["(\\d{4})(\\d{4})","$1 $2",["[369]|8(?:0[1-9]|[1-9])"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8"]],["(\\d{4})(\\d{4})(\\d{3})","$1 $2 $3",["7"]],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3",["1"]]],0,0,0,0,0,0,[0,["896[0-8]\\d{4}|(?:8(?:0[1-9]|[1-8]\\d|9[0-5])|9[0-8]\\d)\\d{5}",[8]]]],SH:["290","00","(?:[256]\\d|8)\\d{3}",[4,5],0,0,0,0,0,0,"[256]",[0,["[56]\\d{4}",[5]]]],SI:["386","00|10(?:22|66|88|99)","[1-7]\\d{7}|8\\d{4,7}|90\\d{4,6}",[5,6,7,8],[["(\\d{2})(\\d{3,6})","$1 $2",["8[09]|9"],"0$1"],["(\\d{3})(\\d{5})","$1 $2",["59|8"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[37][01]|4[0139]|51|6"],"0$1"],["(\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[1-57]"],"(0$1)"]],"0",0,0,0,0,0,[0,["65(?:[178]\\d|5[56]|6[01])\\d{4}|(?:[37][01]|4[0139]|51|6[489])\\d{6}",[8]]],"00"],SJ:["47","00","0\\d{4}|(?:[489]\\d|79)\\d{6}",[5,8],0,0,0,0,0,0,"79",[0,["(?:4[015-8]|9\\d)\\d{6}",[8]]]],SK:["421","00","[2-689]\\d{8}|[2-59]\\d{6}|[2-5]\\d{5}",[6,7,9],[["(\\d)(\\d{2})(\\d{3,4})","$1 $2 $3",["21"],"0$1"],["(\\d{2})(\\d{2})(\\d{2,3})","$1 $2 $3",["[3-5][1-8]1","[3-5][1-8]1[67]"],"0$1"],["(\\d)(\\d{3})(\\d{3})(\\d{2})","$1/$2 $3 $4",["2"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[689]"],"0$1"],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1/$2 $3 $4",["[3-5]"],"0$1"]],"0",0,0,0,0,0,[0,["909[1-9]\\d{5}|9(?:0[1-8]|1[0-24-9]|4[03-57-9]|5\\d)\\d{6}",[9]]]],SL:["232","00","(?:[237-9]\\d|66)\\d{6}",[8],[["(\\d{2})(\\d{6})","$1 $2",["[236-9]"],"(0$1)"]],"0",0,0,0,0,0,[0,["(?:25|3[0-5]|66|7[1-9]|8[08]|9[09])\\d{6}"]]],SM:["378","00","(?:0549|[5-7]\\d)\\d{6}",[8,10],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[5-7]"]],["(\\d{4})(\\d{6})","$1 $2",["0"]]],0,0,"([89]\\d{5})$","0549$1",0,0,[0,["6[16]\\d{6}",[8]]]],SN:["221","00","(?:[378]\\d|93)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"]],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[379]"]]],0,0,0,0,0,0,[0,["7(?:(?:[06-8]\\d|[19]0|21)\\d|5(?:0[01]|[19]0|2[25]|3[356]|[4-7]\\d|8[35]))\\d{5}"]]],SO:["252","00","[346-9]\\d{8}|[12679]\\d{7}|[1-5]\\d{6}|[1348]\\d{5}",[6,7,8,9],[["(\\d{2})(\\d{4})","$1 $2",["8[125]"]],["(\\d{6})","$1",["[134]"]],["(\\d)(\\d{6})","$1 $2",["[15]|2[0-79]|3[0-46-8]|4[0-7]"]],["(\\d)(\\d{7})","$1 $2",["(?:2|90)4|[67]"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[348]|64|79|90"]],["(\\d{2})(\\d{5,7})","$1 $2",["1|28|6[0-35-9]|7[67]|9[2-9]"]]],"0",0,0,0,0,0,[0,["(?:(?:15|(?:3[59]|4[89]|6\\d|7[679]|8[08])\\d|9(?:0\\d|[2-9]))\\d|2(?:4\\d|8))\\d{5}|(?:[67]\\d\\d|904)\\d{5}",[7,8,9]]]],SR:["597","00","(?:[2-5]|68|[78]\\d)\\d{5}",[6,7],[["(\\d{2})(\\d{2})(\\d{2})","$1-$2-$3",["56"]],["(\\d{3})(\\d{3})","$1-$2",["[2-5]"]],["(\\d{3})(\\d{4})","$1-$2",["[6-8]"]]],0,0,0,0,0,0,[0,["(?:7[124-7]|8[1-9])\\d{5}",[7]]]],SS:["211","00","[19]\\d{8}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[19]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:12|9[1257-9])\\d{7}"]]],ST:["239","00","(?:22|9\\d)\\d{5}",[7],[["(\\d{3})(\\d{4})","$1 $2",["[29]"]]],0,0,0,0,0,0,[0,["900[5-9]\\d{3}|9(?:0[1-9]|[89]\\d)\\d{4}"]]],SV:["503","00","[267]\\d{7}|(?:80\\d|900)\\d{4}(?:\\d{4})?",[7,8,11],[["(\\d{3})(\\d{4})","$1 $2",["[89]"]],["(\\d{4})(\\d{4})","$1 $2",["[267]"]],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3",["[89]"]]],0,0,0,0,0,0,[0,["[67]\\d{7}",[8]]]],SX:["1","011","7215\\d{6}|(?:[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"(5\\d{6})$|1","721$1",0,"721",[0,["7215(?:1[02]|2\\d|5[034679]|8[014-8])\\d{4}"]]],SY:["963","00","[1-359]\\d{8}|[1-5]\\d{7}",[8,9],[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[1-4]|5[1-3]"],"0$1",1],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[59]"],"0$1",1]],"0",0,0,0,0,0,[0,["(?:50|9[1-689])\\d{7}",[9]]]],SZ:["268","00","0800\\d{4}|(?:[237]\\d|900)\\d{6}",[8,9],[["(\\d{4})(\\d{4})","$1 $2",["[0237]"]],["(\\d{5})(\\d{4})","$1 $2",["9"]]],0,0,0,0,0,0,[0,["7[6-9]\\d{6}",[8]]]],TA:["290","00","8\\d{3}",[4],0,0,0,0,0,0,"8"],TC:["1","011","(?:[58]\\d\\d|649|900)\\d{7}",[10],0,"1",0,"([2-479]\\d{6})$|1","649$1",0,"649",[0,["649(?:2(?:3[129]|4[1-79])|3\\d\\d|4[34][1-3])\\d{4}"]]],TD:["235","00|16","(?:22|[689]\\d|77)\\d{6}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[26-9]"]]],0,0,0,0,0,0,[0,["(?:[69]\\d|77|8[56])\\d{6}"]],"00"],TG:["228","00","[279]\\d{7}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[279]"]]],0,0,0,0,0,0,[0,["(?:7[0-29]|9[0-36-9])\\d{6}"]]],TH:["66","00[1-9]","(?:001800|[2-57]|[689]\\d)\\d{7}|1\\d{7,9}",[8,9,10,13],[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3",["2"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[13-9]"],"0$1"],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3",["1"]]],"0",0,0,0,0,0,[0,["67(?:1[0-8]|2[4-7])\\d{5}|(?:14|6[1-6]|[89]\\d)\\d{7}",[9]]]],TJ:["992","810","[0-57-9]\\d{8}",[9],[["(\\d{6})(\\d)(\\d{2})","$1 $2 $3",["331","3317"]],["(\\d{3})(\\d{2})(\\d{4})","$1 $2 $3",["44[02-479]|[34]7"]],["(\\d{4})(\\d)(\\d{4})","$1 $2 $3",["3(?:[1245]|3[12])"]],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[0-57-9]"]]],0,0,0,0,0,0,[0,["(?:33[03-9]|4(?:1[18]|4[02-479])|81[1-9])\\d{6}|(?:[09]\\d|1[0-27-9]|2[0-27]|[34]0|5[05]|7[01578]|8[078])\\d{7}"]],"8~10"],TK:["690","00","[2-47]\\d{3,6}",[4,5,6,7],0,0,0,0,0,0,0,[0,["7[2-4]\\d{2,5}"]]],TL:["670","00","7\\d{7}|(?:[2-47]\\d|[89]0)\\d{5}",[7,8],[["(\\d{3})(\\d{4})","$1 $2",["[2-489]|70"]],["(\\d{4})(\\d{4})","$1 $2",["7"]]],0,0,0,0,0,0,[0,["7[2-8]\\d{6}",[8]]]],TM:["993","810","(?:[1-6]\\d|71)\\d{6}",[8],[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2-$3-$4",["12"],"(8 $1)"],["(\\d{3})(\\d)(\\d{2})(\\d{2})","$1 $2-$3-$4",["[1-5]"],"(8 $1)"],["(\\d{2})(\\d{6})","$1 $2",["[67]"],"8 $1"]],"8",0,0,0,0,0,[0,["(?:6\\d|71)\\d{6}"]],"8~10"],TN:["216","00","[2-57-9]\\d{7}",[8],[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[2-57-9]"]]],0,0,0,0,0,0,[0,["3(?:001|[12]40)\\d{4}|(?:(?:[259]\\d|4[0-8])\\d|3(?:1[1-35]|6[0-4]|91))\\d{5}"]]],TO:["676","00","(?:0800|(?:[5-8]\\d\\d|999)\\d)\\d{3}|[2-8]\\d{4}",[5,7],[["(\\d{2})(\\d{3})","$1-$2",["[2-4]|50|6[09]|7[0-24-69]|8[05]"]],["(\\d{4})(\\d{3})","$1 $2",["0"]],["(\\d{3})(\\d{4})","$1 $2",["[5-9]"]]],0,0,0,0,0,0,[0,["(?:5(?:4[0-5]|5[4-6])|6(?:[09]\\d|3[02]|8[15-9])|(?:7\\d|8[46-9])\\d|999)\\d{4}",[7]]]],TR:["90","00","4\\d{6}|8\\d{11,12}|(?:[2-58]\\d\\d|900)\\d{7}",[7,10,12,13],[["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["512|8[01589]|90"],"0$1",1],["(\\d{3})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["5(?:[0-59]|61)","5(?:[0-59]|61[06])","5(?:[0-59]|61[06]1)"],"0$1",1],["(\\d{3})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[24][1-8]|3[1-9]"],"(0$1)",1],["(\\d{3})(\\d{3})(\\d{6,7})","$1 $2 $3",["80"],"0$1",1]],"0",0,0,0,0,0,[0,["561(?:011|61\\d)\\d{4}|5(?:0[15-7]|1[06]|24|[34]\\d|5[1-59]|9[46])\\d{7}",[10]]]],TT:["1","011","(?:[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-46-8]\\d{6})$|1","868$1",0,"868",[0,["868(?:(?:2[5-9]|3\\d)\\d|4(?:3[0-6]|[6-9]\\d)|6(?:20|78|8\\d)|7(?:0[1-9]|1[02-9]|[2-9]\\d))\\d{4}"]]],TV:["688","00","(?:2|7\\d\\d|90)\\d{4}",[5,6,7],[["(\\d{2})(\\d{3})","$1 $2",["2"]],["(\\d{2})(\\d{4})","$1 $2",["90"]],["(\\d{2})(\\d{5})","$1 $2",["7"]]],0,0,0,0,0,0,[0,["(?:7[01]\\d|90)\\d{4}",[6,7]]]],TW:["886","0(?:0[25-79]|19)","[2-689]\\d{8}|7\\d{9,10}|[2-8]\\d{7}|2\\d{6}",[7,8,9,10,11],[["(\\d{2})(\\d)(\\d{4})","$1 $2 $3",["202"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["[258]0"],"0$1"],["(\\d)(\\d{3,4})(\\d{4})","$1 $2 $3",["[23568]|4(?:0[02-48]|[1-47-9])|7[1-9]","[23568]|4(?:0[2-48]|[1-47-9])|(?:400|7)[1-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[49]"],"0$1"],["(\\d{2})(\\d{4})(\\d{4,5})","$1 $2 $3",["7"],"0$1"]],"0",0,0,0,0,0,[0,["(?:40001[0-2]|9[0-8]\\d{4})\\d{3}",[9]]],0,"#"],TZ:["255","00[056]","(?:[25-8]\\d|41|90)\\d{7}",[9],[["(\\d{3})(\\d{2})(\\d{4})","$1 $2 $3",["[89]"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[24]"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["5"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[67]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:6[125-9]|7[13-9])\\d{7}"]]],UA:["380","00","[89]\\d{9}|[3-9]\\d{8}",[9,10],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["6[12][29]|(?:3[1-8]|4[136-8]|5[12457]|6[49])2|(?:56|65)[24]","6[12][29]|(?:35|4[1378]|5[12457]|6[49])2|(?:56|65)[24]|(?:3[1-46-8]|46)2[013-9]"],"0$1"],["(\\d{4})(\\d{5})","$1 $2",["3[1-8]|4(?:[1367]|[45][6-9]|8[4-6])|5(?:[1-5]|6[0135689]|7[4-6])|6(?:[12][3-7]|[459])","3[1-8]|4(?:[1367]|[45][6-9]|8[4-6])|5(?:[1-5]|6(?:[015689]|3[02389])|7[4-6])|6(?:[12][3-7]|[459])"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[3-7]|89|9[1-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["[89]"],"0$1"]],"0",0,0,0,0,0,[0,["790\\d{6}|(?:39|50|6[36-8]|7[1-357]|9[1-9])\\d{7}",[9]]],"0~0"],UG:["256","00[057]","800\\d{6}|(?:[29]0|[347]\\d)\\d{7}",[9],[["(\\d{4})(\\d{5})","$1 $2",["202","2024"],"0$1"],["(\\d{3})(\\d{6})","$1 $2",["[27-9]|4(?:6[45]|[7-9])"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["[34]"],"0$1"]],"0",0,0,0,0,0,[0,["72[48]0\\d{5}|7(?:[015-8]\\d|2[067]|36|4[0-8]|9[089])\\d{6}"]]],US:["1","011","[2-9]\\d{9}|3\\d{6}",[10],[["(\\d{3})(\\d{4})","$1-$2",["310"],0,1],["(\\d{3})(\\d{3})(\\d{4})","($1) $2-$3",["[2-9]"],0,1,"$1-$2-$3"]],"1",0,0,0,0,0,[0,["(?:3052(?:0[0-8]|[1-9]\\d)|5056(?:[0-35-9]\\d|4[0-468]))\\d{4}|(?:2742|305[3-9]|472[247-9]|505[2-57-9]|983[2-47-9])\\d{6}|(?:2(?:0[1-35-9]|1[02-9]|2[03-57-9]|3[1459]|4[08]|5[1-46]|6[0279]|7[0269]|8[13])|3(?:0[1-47-9]|1[02-9]|2[0135-79]|3[0-24679]|4[167]|5[0-2]|6[01349]|8[056])|4(?:0[124-9]|1[02-579]|2[3-5]|3[0245]|4[023578]|58|6[349]|7[0589]|8[04])|5(?:0[1-47-9]|1[0235-8]|20|3[0149]|4[01]|5[179]|6[1-47]|7[0-5]|8[0256])|6(?:0[1-35-9]|1[024-9]|2[03689]|3[016]|4[0156]|5[01679]|6[0-279]|78|8[0-29])|7(?:0[1-46-8]|1[2-9]|2[04-8]|3[0-247]|4[037]|5[47]|6[02359]|7[0-59]|8[156])|8(?:0[1-68]|1[02-8]|2[068]|3[0-2589]|4[03578]|5[046-9]|6[02-5]|7[028])|9(?:0[1346-9]|1[02-9]|2[0589]|3[0146-8]|4[01357-9]|5[12469]|7[0-389]|8[04-69]))[2-9]\\d{6}"]]],UY:["598","0(?:0|1[3-9]\\d)","0004\\d{2,9}|[1249]\\d{7}|(?:[49]\\d|80)\\d{5}",[6,7,8,9,10,11,12,13],[["(\\d{3})(\\d{3,4})","$1 $2",["0"]],["(\\d{3})(\\d{4})","$1 $2",["[49]0|8"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["9"],"0$1"],["(\\d{4})(\\d{4})","$1 $2",["[124]"]],["(\\d{3})(\\d{3})(\\d{2,4})","$1 $2 $3",["0"]],["(\\d{3})(\\d{3})(\\d{3})(\\d{2,4})","$1 $2 $3 $4",["0"]]],"0",0,0,0,0,0,[0,["9[1-9]\\d{6}",[8]]],"00"," int. "],UZ:["998","00","(?:20|33|[5-9]\\d)\\d{7}",[9],[["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["[235-9]"]]],0,0,0,0,0,0,[0,["(?:(?:[25]0|33|8[78]|9[0-57-9])\\d{3}|6(?:1(?:2(?:2[01]|98)|35[0-4]|50\\d|61[23]|7(?:[01][017]|4\\d|55|9[5-9]))|2(?:(?:11|7\\d)\\d|2(?:[12]1|9[01379])|5(?:[126]\\d|3[0-4]))|5(?:19[01]|2(?:27|9[26])|(?:30|59|7\\d)\\d)|6(?:2(?:1[5-9]|2[0367]|38|41|52|60)|(?:3[79]|9[0-3])\\d|4(?:56|83)|7(?:[07]\\d|1[017]|3[07]|4[047]|5[057]|67|8[0178]|9[79]))|7(?:2(?:24|3[237]|4[5-9]|7[15-8])|5(?:7[12]|8[0589])|7(?:0\\d|[39][07])|9(?:0\\d|7[079])))|7(?:[07]\\d{3}|1(?:13[01]|6(?:0[47]|1[67]|66)|71[3-69]|98\\d)|2(?:2(?:2[79]|95)|3(?:2[5-9]|6[0-6])|57\\d|7(?:0\\d|1[17]|2[27]|3[37]|44|5[057]|66|88))|3(?:2(?:1[0-6]|21|3[469]|7[159])|(?:33|9[4-6])\\d|5(?:0[0-4]|5[579]|9\\d)|7(?:[0-3579]\\d|4[0467]|6[67]|8[078]))|4(?:2(?:29|5[0257]|6[0-7]|7[1-57])|5(?:1[0-4]|8\\d|9[5-9])|7(?:0\\d|1[024589]|2[0-27]|3[0137]|[46][07]|5[01]|7[5-9]|9[079])|9(?:7[015-9]|[89]\\d))|5(?:112|2(?:0\\d|2[29]|[49]4)|3[1568]\\d|52[6-9]|7(?:0[01578]|1[017]|[23]7|4[047]|[5-7]\\d|8[78]|9[079]))|9(?:22[128]|3(?:2[0-4]|7\\d)|57[02569]|7(?:2[05-9]|3[37]|4\\d|60|7[2579]|87|9[07]))))\\d{4}"]]],VA:["39","00","0\\d{5,10}|3[0-8]\\d{7,10}|55\\d{8}|8\\d{5}(?:\\d{2,4})?|(?:1\\d|39)\\d{7,8}",[6,7,8,9,10,11,12],0,0,0,0,0,0,"06698",[0,["3[1-9]\\d{8}|3[2-9]\\d{7}",[9,10]]]],VC:["1","011","(?:[58]\\d\\d|784|900)\\d{7}",[10],0,"1",0,"([2-7]\\d{6})$|1","784$1",0,"784",[0,["784(?:4(?:3[0-5]|5[45]|89|9[0-8])|5(?:2[6-9]|3[0-4])|720)\\d{4}"]]],VE:["58","00","[68]00\\d{7}|(?:[24]\\d|[59]0)\\d{8}",[10],[["(\\d{3})(\\d{7})","$1-$2",["[24-689]"],"0$1"]],"0",0,0,0,0,0,[0,["4(?:1[24-8]|2[246])\\d{7}"]]],VG:["1","011","(?:284|[58]\\d\\d|900)\\d{7}",[10],0,"1",0,"([2-578]\\d{6})$|1","284$1",0,"284",[0,["284(?:245|3(?:0[0-3]|4[0-7]|68|9[34])|4(?:4[0-6]|68|9[69])|5(?:4[0-7]|68|9[69]))\\d{4}"]]],VI:["1","011","[58]\\d{9}|(?:34|90)0\\d{7}",[10],0,"1",0,"([2-9]\\d{6})$|1","340$1",0,"340",[0,["340(?:2(?:0\\d|10|2[06-8]|4[49]|77)|3(?:32|44)|4(?:2[23]|44|7[34]|89)|5(?:1[34]|55)|6(?:2[56]|4[23]|77|9[023])|7(?:1[2-57-9]|2[57]|7\\d)|884|998)\\d{4}"]]],VN:["84","00","[12]\\d{9}|[135-9]\\d{8}|[16]\\d{7}|[16-8]\\d{6}",[7,8,9,10],[["(\\d{2})(\\d{5})","$1 $2",["80"],"0$1",1],["(\\d{4})(\\d{4,6})","$1 $2",["1"],0,1],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",["6"],"0$1",1],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[357-9]"],"0$1",1],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["2[48]"],"0$1",1],["(\\d{3})(\\d{4})(\\d{3})","$1 $2 $3",["2"],"0$1",1]],"0",0,0,0,0,0,[0,["(?:5(?:2[238]|59)|89[6-9]|99[013-9])\\d{6}|(?:3\\d|5[1689]|7[06-9]|8[1-8]|9[0-8])\\d{7}",[9]]]],VU:["678","00","[57-9]\\d{6}|(?:[238]\\d|48)\\d{3}",[5,7],[["(\\d{3})(\\d{4})","$1 $2",["[57-9]"]]],0,0,0,0,0,0,[0,["(?:[58]\\d|7[013-7])\\d{5}",[7]]]],WF:["681","00","(?:40|72|8\\d{4})\\d{4}|[89]\\d{5}",[6,9],[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",["[47-9]"]],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",["8"]]],0,0,0,0,0,0,[0,["(?:72|8[23])\\d{4}",[6]]]],WS:["685","0","(?:[2-6]|8\\d{5})\\d{4}|[78]\\d{6}|[68]\\d{5}",[5,6,7,10],[["(\\d{5})","$1",["[2-5]|6[1-9]"]],["(\\d{3})(\\d{3,7})","$1 $2",["[68]"]],["(\\d{2})(\\d{5})","$1 $2",["7"]]],0,0,0,0,0,0,[0,["(?:7[1-35-7]|8(?:[3-7]|9\\d{3}))\\d{5}",[7,10]]]],XK:["383","00","2\\d{7,8}|3\\d{7,11}|(?:4\\d\\d|[89]00)\\d{5}",[8,9,10,11,12],[["(\\d{3})(\\d{5})","$1 $2",["[89]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",["[2-4]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["2|39"],"0$1"],["(\\d{2})(\\d{7,10})","$1 $2",["3"],"0$1"]],"0",0,0,0,0,0,[0,["4[3-9]\\d{6}",[8]]]],YE:["967","00","(?:1|7\\d)\\d{7}|[1-7]\\d{6}",[7,8,9],[["(\\d)(\\d{3})(\\d{3,4})","$1 $2 $3",["[1-6]|7(?:[24-6]|8[0-7])"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["7"],"0$1"]],"0",0,0,0,0,0,[0,["7[01378]\\d{7}",[9]]]],YT:["262","00","7093\\d{5}|(?:80|9\\d)\\d{7}|(?:26|63)9\\d{6}",[9],0,"0",0,0,0,0,0,[0,["(?:639(?:0[0-79]|1[019]|[267]\\d|3[09]|40|5[05-9]|9[04-79])|7093[5-7])\\d{4}"]]],ZA:["27","00","[1-79]\\d{8}|8\\d{4,9}",[5,6,7,8,9,10],[["(\\d{2})(\\d{3,4})","$1 $2",["8[1-4]"],"0$1"],["(\\d{2})(\\d{3})(\\d{2,3})","$1 $2 $3",["8[1-4]"],"0$1"],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["860"],"0$1"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["[1-9]"],"0$1"],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["8"],"0$1"]],"0",0,0,0,0,0,[0,["(?:1(?:3492[0-25]|4495[0235]|549(?:20|5[01]))|4[34]492[01])\\d{3}|8[1-4]\\d{3,7}|(?:2[27]|47|54)4950\\d{3}|(?:1(?:049[2-4]|9[12]\\d\\d)|(?:6\\d\\d|7(?:[0-46-9]\\d|5[0-4]))\\d\\d|8(?:5\\d{3}|7(?:08[67]|158|28[5-9]|310)))\\d{4}|(?:1[6-8]|28|3[2-69]|4[025689]|5[36-8])4920\\d{3}|(?:12|[2-5]1)492\\d{4}",[5,6,7,8,9]]]],ZM:["260","00","800\\d{6}|(?:21|[579]\\d|63)\\d{7}",[9],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[28]"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["[579]"],"0$1"]],"0",0,0,0,0,0,[0,["(?:[59][5-8]|7[5-9])\\d{7}"]]],ZW:["263","00","2(?:[0-57-9]\\d{6,8}|6[0-24-9]\\d{6,7})|[38]\\d{9}|[35-8]\\d{8}|[3-6]\\d{7}|[1-689]\\d{6}|[1-3569]\\d{5}|[1356]\\d{4}",[5,6,7,8,9,10],[["(\\d{3})(\\d{3,5})","$1 $2",["2(?:0[45]|2[278]|[49]8)|3(?:[09]8|17)|6(?:[29]8|37|75)|[23][78]|(?:33|5[15]|6[68])[78]"],"0$1"],["(\\d)(\\d{3})(\\d{2,4})","$1 $2 $3",["[49]"],"0$1"],["(\\d{3})(\\d{4})","$1 $2",["80"],"0$1"],["(\\d{2})(\\d{7})","$1 $2",["24|8[13-59]|(?:2[05-79]|39|5[45]|6[15-8])2","2(?:02[014]|4|[56]20|[79]2)|392|5(?:42|525)|6(?:[16-8]21|52[013])|8[13-59]"],"(0$1)"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",["7"],"0$1"],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3",["2(?:1[39]|2[0157]|[378]|[56][14])|3(?:12|29)","2(?:1[39]|2[0157]|[378]|[56][14])|3(?:123|29)"],"0$1"],["(\\d{4})(\\d{6})","$1 $2",["8"],"0$1"],["(\\d{2})(\\d{3,5})","$1 $2",["1|2(?:0[0-36-9]|12|29|[56])|3(?:1[0-689]|[24-6])|5(?:[0236-9]|1[2-4])|6(?:[013-59]|7[0-46-9])|(?:33|55|6[68])[0-69]|(?:29|3[09]|62)[0-79]"],"0$1"],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3",["29[013-9]|39|54"],"0$1"],["(\\d{4})(\\d{3,5})","$1 $2",["(?:25|54)8","258|5483"],"0$1"]],"0",0,0,0,0,0,[0,["7(?:[1278]\\d|3[1-9])\\d{6}",[9]]]]},nonGeographic:{800:["800",0,"(?:00|[1-9]\\d)\\d{6}",[8],[["(\\d{4})(\\d{4})","$1 $2",["\\d"]]],0,0,0,0,0,0,[0,0,["(?:00|[1-9]\\d)\\d{6}"]]],808:["808",0,"[1-9]\\d{7}",[8],[["(\\d{4})(\\d{4})","$1 $2",["[1-9]"]]],0,0,0,0,0,0,[0,0,0,0,0,0,0,0,0,["[1-9]\\d{7}"]]],870:["870",0,"7\\d{11}|[235-7]\\d{8}",[9,12],[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["[235-7]"]]],0,0,0,0,0,0,[0,["(?:[356]|774[45])\\d{8}|7[6-8]\\d{7}"],0,0,0,0,0,0,["2\\d{8}",[9]]]],878:["878",0,"10\\d{10}",[12],[["(\\d{2})(\\d{5})(\\d{5})","$1 $2 $3",["1"]]],0,0,0,0,0,0,[0,0,0,0,0,0,0,0,["10\\d{10}"]]],881:["881",0,"6\\d{9}|[0-36-9]\\d{8}",[9,10],[["(\\d)(\\d{3})(\\d{5})","$1 $2 $3",["[0-37-9]"]],["(\\d)(\\d{3})(\\d{5,6})","$1 $2 $3",["6"]]],0,0,0,0,0,0,[0,["6\\d{9}|[0-36-9]\\d{8}"]]],882:["882",0,"[13]\\d{6}(?:\\d{2,5})?|[19]\\d{7}|(?:[25]\\d\\d|4)\\d{7}(?:\\d{2})?",[7,8,9,10,11,12],[["(\\d{2})(\\d{5})","$1 $2",["16|342"]],["(\\d{2})(\\d{6})","$1 $2",["49"]],["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",["1[36]|9"]],["(\\d{2})(\\d{4})(\\d{3})","$1 $2 $3",["3[23]"]],["(\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3",["16"]],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3",["10|23|3(?:[15]|4[57])|4|51"]],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3",["34"]],["(\\d{2})(\\d{4,5})(\\d{5})","$1 $2 $3",["[1-35]"]]],0,0,0,0,0,0,[0,["342\\d{4}|(?:337|49)\\d{6}|(?:3(?:2|47|7\\d{3})|50\\d{3})\\d{7}",[7,8,9,10,12]],0,0,0,["348[57]\\d{7}",[11]],0,0,["1(?:3(?:0[0347]|[13][0139]|2[035]|4[013568]|6[0459]|7[06]|8[15-8]|9[0689])\\d{4}|6\\d{5,10})|(?:345\\d|9[89])\\d{6}|(?:10|2(?:3|85\\d)|3(?:[15]|[69]\\d\\d)|4[15-8]|51)\\d{8}"]]],883:["883",0,"(?:[1-4]\\d|51)\\d{6,10}",[8,9,10,11,12],[["(\\d{3})(\\d{3})(\\d{2,8})","$1 $2 $3",["[14]|2[24-689]|3[02-689]|51[24-9]"]],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",["510"]],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3",["21"]],["(\\d{4})(\\d{4})(\\d{4})","$1 $2 $3",["51[13]"]],["(\\d{3})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",["[235]"]]],0,0,0,0,0,0,[0,0,0,0,0,0,0,0,["(?:2(?:00\\d\\d|10)|(?:370[1-9]|51\\d0)\\d)\\d{7}|51(?:00\\d{5}|[24-9]0\\d{4,7})|(?:1[0-79]|2[24-689]|3[02-689]|4[0-4])0\\d{5,9}"]]],888:["888",0,"\\d{11}",[11],[["(\\d{3})(\\d{3})(\\d{5})","$1 $2 $3"]],0,0,0,0,0,0,[0,0,0,0,0,0,["\\d{11}"]]],979:["979",0,"[1359]\\d{8}",[9],[["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",["[1359]"]]],0,0,0,0,0,0,[0,0,0,["[1359]\\d{8}"]]]}};function d(t,d){var n=Array.prototype.slice.call(d);return n.push(e),t.apply(this,n)}function n(t,e){t=t.split("-"),e=e.split("-");for(var d=t[0].split("."),n=e[0].split("."),r=0;r<3;r++){var a=Number(d[r]),i=Number(n[r]);if(a>i)return 1;if(i>a)return-1;if(!isNaN(a)&&isNaN(i))return 1;if(isNaN(a)&&!isNaN(i))return-1}return t[1]&&e[1]?t[1]>e[1]?1:t[1]<e[1]?-1:0:!t[1]&&e[1]?1:t[1]&&!e[1]?-1:0}var r={}.constructor;function a(t){return null!=t&&t.constructor===r}function i(t){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},i(t)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function $(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function u(t,e,d){return e&&$(t.prototype,e),d&&$(t,d),Object.defineProperty(t,"prototype",{writable:!1}),t}var l=" ext. ",c=/^\d+$/,s=function(){function t(e){o(this,t),p(e),this.metadata=e,P.call(this,e)}return u(t,[{key:"getCountries",value:function(){return Object.keys(this.metadata.countries).filter((function(t){return"001"!==t}))}},{key:"getCountryMetadata",value:function(t){return this.metadata.countries[t]}},{key:"nonGeographic",value:function(){if(!(this.v1||this.v2||this.v3))return this.metadata.nonGeographic||this.metadata.nonGeographical}},{key:"hasCountry",value:function(t){return void 0!==this.getCountryMetadata(t)}},{key:"hasCallingCode",value:function(t){if(this.getCountryCodesForCallingCode(t))return!0;if(this.nonGeographic()){if(this.nonGeographic()[t])return!0}else{var e=this.countryCallingCodes()[t];if(e&&1===e.length&&"001"===e[0])return!0}}},{key:"isNonGeographicCallingCode",value:function(t){return this.nonGeographic()?!!this.nonGeographic()[t]:!this.getCountryCodesForCallingCode(t)}},{key:"country",value:function(t){return this.selectNumberingPlan(t)}},{key:"selectNumberingPlan",value:function(t,e){if(t&&c.test(t)&&(e=t,t=null),t&&"001"!==t){if(!this.hasCountry(t))throw new Error("Unknown country: ".concat(t));this.numberingPlan=new f(this.getCountryMetadata(t),this)}else if(e){if(!this.hasCallingCode(e))throw new Error("Unknown calling code: ".concat(e));this.numberingPlan=new f(this.getNumberingPlanMetadata(e),this)}else this.numberingPlan=void 0;return this}},{key:"getCountryCodesForCallingCode",value:function(t){var e=this.countryCallingCodes()[t];if(e){if(1===e.length&&3===e[0].length)return;return e}}},{key:"getCountryCodeForCallingCode",value:function(t){var e=this.getCountryCodesForCallingCode(t);if(e)return e[0]}},{key:"getNumberingPlanMetadata",value:function(t){var e=this.getCountryCodeForCallingCode(t);if(e)return this.getCountryMetadata(e);if(this.nonGeographic()){var d=this.nonGeographic()[t];if(d)return d}else{var n=this.countryCallingCodes()[t];if(n&&1===n.length&&"001"===n[0])return this.metadata.countries["001"]}}},{key:"countryCallingCode",value:function(){return this.numberingPlan.callingCode()}},{key:"IDDPrefix",value:function(){return this.numberingPlan.IDDPrefix()}},{key:"defaultIDDPrefix",value:function(){return this.numberingPlan.defaultIDDPrefix()}},{key:"nationalNumberPattern",value:function(){return this.numberingPlan.nationalNumberPattern()}},{key:"possibleLengths",value:function(){return this.numberingPlan.possibleLengths()}},{key:"formats",value:function(){return this.numberingPlan.formats()}},{key:"nationalPrefixForParsing",value:function(){return this.numberingPlan.nationalPrefixForParsing()}},{key:"nationalPrefixTransformRule",value:function(){return this.numberingPlan.nationalPrefixTransformRule()}},{key:"leadingDigits",value:function(){return this.numberingPlan.leadingDigits()}},{key:"hasTypes",value:function(){return this.numberingPlan.hasTypes()}},{key:"type",value:function(t){return this.numberingPlan.type(t)}},{key:"ext",value:function(){return this.numberingPlan.ext()}},{key:"countryCallingCodes",value:function(){return this.v1?this.metadata.country_phone_code_to_countries:this.metadata.country_calling_codes}},{key:"chooseCountryByCountryCallingCode",value:function(t){return this.selectNumberingPlan(t)}},{key:"hasSelectedNumberingPlan",value:function(){return void 0!==this.numberingPlan}}]),t}(),f=function(){function t(e,d){o(this,t),this.globalMetadataObject=d,this.metadata=e,P.call(this,d.metadata)}return u(t,[{key:"callingCode",value:function(){return this.metadata[0]}},{key:"getDefaultCountryMetadataForRegion",value:function(){return this.globalMetadataObject.getNumberingPlanMetadata(this.callingCode())}},{key:"IDDPrefix",value:function(){if(!this.v1&&!this.v2)return this.metadata[1]}},{key:"defaultIDDPrefix",value:function(){if(!this.v1&&!this.v2)return this.metadata[12]}},{key:"nationalNumberPattern",value:function(){return this.v1||this.v2?this.metadata[1]:this.metadata[2]}},{key:"possibleLengths",value:function(){if(!this.v1)return this.metadata[this.v2?2:3]}},{key:"_getFormats",value:function(t){return t[this.v1?2:this.v2?3:4]}},{key:"formats",value:function(){var t=this,e=this._getFormats(this.metadata)||this._getFormats(this.getDefaultCountryMetadataForRegion())||[];return e.map((function(e){return new h(e,t)}))}},{key:"nationalPrefix",value:function(){return this.metadata[this.v1?3:this.v2?4:5]}},{key:"_getNationalPrefixFormattingRule",value:function(t){return t[this.v1?4:this.v2?5:6]}},{key:"nationalPrefixFormattingRule",value:function(){return this._getNationalPrefixFormattingRule(this.metadata)||this._getNationalPrefixFormattingRule(this.getDefaultCountryMetadataForRegion())}},{key:"_nationalPrefixForParsing",value:function(){return this.metadata[this.v1?5:this.v2?6:7]}},{key:"nationalPrefixForParsing",value:function(){return this._nationalPrefixForParsing()||this.nationalPrefix()}},{key:"nationalPrefixTransformRule",value:function(){return this.metadata[this.v1?6:this.v2?7:8]}},{key:"_getNationalPrefixIsOptionalWhenFormatting",value:function(){return!!this.metadata[this.v1?7:this.v2?8:9]}},{key:"nationalPrefixIsOptionalWhenFormattingInNationalFormat",value:function(){return this._getNationalPrefixIsOptionalWhenFormatting(this.metadata)||this._getNationalPrefixIsOptionalWhenFormatting(this.getDefaultCountryMetadataForRegion())}},{key:"leadingDigits",value:function(){return this.metadata[this.v1?8:this.v2?9:10]}},{key:"types",value:function(){return this.metadata[this.v1?9:this.v2?10:11]}},{key:"hasTypes",value:function(){return(!this.types()||0!==this.types().length)&&!!this.types()}},{key:"type",value:function(t){if(this.hasTypes()&&m(this.types(),t))return new y(m(this.types(),t),this)}},{key:"ext",value:function(){return this.v1||this.v2?l:this.metadata[13]||l}}]),t}(),h=function(){function t(e,d){o(this,t),this._format=e,this.metadata=d}return u(t,[{key:"pattern",value:function(){return this._format[0]}},{key:"format",value:function(){return this._format[1]}},{key:"leadingDigitsPatterns",value:function(){return this._format[2]||[]}},{key:"nationalPrefixFormattingRule",value:function(){return this._format[3]||this.metadata.nationalPrefixFormattingRule()}},{key:"nationalPrefixIsOptionalWhenFormattingInNationalFormat",value:function(){return!!this._format[4]||this.metadata.nationalPrefixIsOptionalWhenFormattingInNationalFormat()}},{key:"nationalPrefixIsMandatoryWhenFormattingInNationalFormat",value:function(){return this.usesNationalPrefix()&&!this.nationalPrefixIsOptionalWhenFormattingInNationalFormat()}},{key:"usesNationalPrefix",value:function(){return!(!this.nationalPrefixFormattingRule()||g.test(this.nationalPrefixFormattingRule()))}},{key:"internationalFormat",value:function(){return this._format[5]||this.format()}}]),t}(),g=/^\(?\$1\)?$/,y=function(){function t(e,d){o(this,t),this.type=e,this.metadata=d}return u(t,[{key:"pattern",value:function(){return this.metadata.v1?this.type:this.type[0]}},{key:"possibleLengths",value:function(){if(!this.metadata.v1)return this.type[1]||this.metadata.possibleLengths()}}]),t}();function m(t,e){switch(e){case"FIXED_LINE":return t[0];case"MOBILE":return t[1];case"TOLL_FREE":return t[2];case"PREMIUM_RATE":return t[3];case"PERSONAL_NUMBER":return t[4];case"VOICEMAIL":return t[5];case"UAN":return t[6];case"PAGER":return t[7];case"VOIP":return t[8];case"SHARED_COST":return t[9]}}function p(t){if(!t)throw new Error("[libphonenumber-js] `metadata` argument not passed. Check your arguments.");if(!a(t)||!a(t.countries))throw new Error("[libphonenumber-js] `metadata` argument was passed but it's not a valid metadata. Must be an object having `.countries` child object property. Got ".concat(a(t)?"an object of shape: { "+Object.keys(t).join(", ")+" }":"a "+b(t)+": "+t,"."))}var b=function(t){return i(t)};function v(t,e){return(e=new s(e)).hasCountry(t)?e.country(t).ext():l}function C(t,e){if((e=new s(e)).hasCountry(t))return e.country(t).countryCallingCode();throw new Error("Unknown country: ".concat(t))}function N(t,e){return e.countries.hasOwnProperty(t)}function P(t){var e=t.version;"number"==typeof e?(this.v1=1===e,this.v2=2===e,this.v3=3===e,this.v4=4===e):e?-1===n(e,"1.2.0")?this.v2=!0:-1===n(e,"1.7.35")?this.v3=!0:this.v4=!0:this.v1=!0}function O(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return x(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return x(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function x(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function w(t,e){return S(t,void 0,e)}function S(t,e,d){var n=d.type(e),r=n&&n.possibleLengths()||d.possibleLengths();if(!r)return"IS_POSSIBLE";if("FIXED_LINE_OR_MOBILE"===e){if(!d.type("FIXED_LINE"))return S(t,"MOBILE",d);var a=d.type("MOBILE");a&&(r=function(t,e){for(var d,n=t.slice(),r=O(e);!(d=r()).done;){var a=d.value;t.indexOf(a)<0&&n.push(a)}return n.sort((function(t,e){return t-e}))}(r,a.possibleLengths()))}else if(e&&!n)return"INVALID_LENGTH";var i=t.length,o=r[0];return o===i?"IS_POSSIBLE":o>i?"TOO_SHORT":r[r.length-1]<i?"TOO_LONG":r.indexOf(i,1)>=0?"IS_POSSIBLE":"INVALID_LENGTH"}function E(t,e){return"IS_POSSIBLE"===w(t,e)}function I(t,e){return t=t||"",new RegExp("^(?:"+e+")$").test(t)}function A(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return T(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return T(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function T(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}var j=["MOBILE","PREMIUM_RATE","TOLL_FREE","SHARED_COST","VOIP","PERSONAL_NUMBER","PAGER","UAN","VOICEMAIL"];function k(t,e,d){if(e=e||{},t.country||t.countryCallingCode){(d=new s(d)).selectNumberingPlan(t.country,t.countryCallingCode);var n=e.v2?t.nationalNumber:t.phone;if(I(n,d.nationalNumberPattern())){if(F(n,"FIXED_LINE",d))return d.type("MOBILE")&&""===d.type("MOBILE").pattern()?"FIXED_LINE_OR_MOBILE":d.type("MOBILE")?F(n,"MOBILE",d)?"FIXED_LINE_OR_MOBILE":"FIXED_LINE":"FIXED_LINE_OR_MOBILE";for(var r,a=A(j);!(r=a()).done;){var i=r.value;if(F(n,i,d))return i}}}}function F(t,e,d){return!(!(e=d.type(e))||!e.pattern())&&(!(e.possibleLengths()&&e.possibleLengths().indexOf(t.length)<0)&&I(t,e.pattern()))}function M(t,e,d){var n=new s(d).getCountryCodesForCallingCode(t);return n?n.filter((function(t){return function(t,e,d){var n=new s(d);if(n.selectNumberingPlan(e),n.numberingPlan.possibleLengths().indexOf(t.length)>=0)return!0;return!1}(e,t,d)})):[]}var D="0-9０-９٠-٩۰-۹",R="".concat("-‐-―−ー－").concat("／/").concat("．.").concat("  ­​⁠　").concat("()（）［］\\[\\]").concat("~⁓∼～"),_="+＋",L=new RegExp("([0-9０-９٠-٩۰-۹])");function G(t,e,d,n){if(e){var r=new s(n);r.selectNumberingPlan(e,d);var a=new RegExp(r.IDDPrefix());if(0===t.search(a)){var i=(t=t.slice(t.match(a)[0].length)).match(L);if(!(i&&null!=i[1]&&i[1].length>0&&"0"===i[1]))return t}}}function B(t,e){if(t&&e.numberingPlan.nationalPrefixForParsing()){var d=new RegExp("^(?:"+e.numberingPlan.nationalPrefixForParsing()+")"),n=d.exec(t);if(n){var r,a,i,o=n.length-1,$=o>0&&n[o];if(e.nationalPrefixTransformRule()&&$)r=t.replace(d,e.nationalPrefixTransformRule()),o>1&&(a=n[1]);else{var u=n[0];r=t.slice(u.length),$&&(a=n[1])}if($){var l=t.indexOf(n[1]);t.slice(0,l)===e.numberingPlan.nationalPrefix()&&(i=e.numberingPlan.nationalPrefix())}else i=n[0];return{nationalNumber:r,nationalPrefix:i,carrierCode:a}}}return{nationalNumber:t}}function U(t,e){var d=B(t,e),n=d.carrierCode,r=d.nationalNumber;if(r!==t){if(!function(t,e,d){if(I(t,d.nationalNumberPattern())&&!I(e,d.nationalNumberPattern()))return!1;return!0}(t,r,e))return{nationalNumber:t};if(e.possibleLengths()&&!function(t,e){switch(w(t,e)){case"TOO_SHORT":case"INVALID_LENGTH":return!1;default:return!0}}(r,e))return{nationalNumber:t}}return{nationalNumber:r,carrierCode:n}}function H(t,e,d,n){var r=e?C(e,n):d;if(0===t.indexOf(r)){(n=new s(n)).selectNumberingPlan(e,d);var a=t.slice(r.length),i=U(a,n).nationalNumber,o=U(t,n).nationalNumber;if(!I(o,n.nationalNumberPattern())&&I(i,n.nationalNumberPattern())||"TOO_LONG"===w(o,n))return{countryCallingCode:r,number:a}}return{number:t}}function W(t,e,d,n){if(!t)return{};var r;if("+"!==t[0]){var a=G(t,e,d,n);if(!a||a===t){if(e||d){var i=H(t,e,d,n),o=i.countryCallingCode,$=i.number;if(o)return{countryCallingCodeSource:"FROM_NUMBER_WITHOUT_PLUS_SIGN",countryCallingCode:o,number:$}}return{number:t}}r=!0,t="+"+a}if("0"===t[1])return{};n=new s(n);for(var u=2;u-1<=3&&u<=t.length;){var l=t.slice(1,u);if(n.hasCallingCode(l))return n.selectNumberingPlan(l),{countryCallingCodeSource:r?"FROM_NUMBER_WITH_IDD":"FROM_NUMBER_WITH_PLUS_SIGN",countryCallingCode:l,number:t.slice(u)};u++}return{}}function V(t){return t.replace(new RegExp("[".concat(R,"]+"),"g")," ").trim()}var K=/(\$\d)/;function Y(t,e,d){var n=d.useInternationalFormat,r=d.withNationalPrefix;d.carrierCode,d.metadata;var a=t.replace(new RegExp(e.pattern()),n?e.internationalFormat():r&&e.nationalPrefixFormattingRule()?e.format().replace(K,e.nationalPrefixFormattingRule()):e.format());return n?V(a):a}var Z=/^[\d]+(?:[~\u2053\u223C\uFF5E][\d]+)?$/;var X=function(t){return"([".concat(D,"]{1,").concat(t,"})")};function J(t){var e="#?";return";ext="+X("20")+"|"+("[  \\t,]*(?:e?xt(?:ensi(?:ó?|ó))?n?|ｅ?ｘｔｎ?|доб|anexo)[:\\.．]?[  \\t,-]*"+X("20")+e)+"|"+("[  \\t,]*(?:[xｘ#＃~～]|int|ｉｎｔ)[:\\.．]?[  \\t,-]*"+X("9")+e)+"|"+("[- ]+"+X("6")+"#")+"|"+("[  \\t]*(?:,{2}|;)[:\\.．]?[  \\t,-]*"+X("15")+e)+"|"+("[  \\t]*(?:,)+[:\\.．]?[  \\t,-]*"+X("9")+e)}var Q="[+＋]{0,1}(?:["+R+"]*["+"0-9０-９٠-٩۰-۹]){3,}["+R+"0-9０-９٠-٩۰-۹]*",z=new RegExp("^[+＋]{0,1}(?:["+R+"]*["+"0-9０-９٠-٩۰-۹]){1,2}$","i"),q=Q+"(?:"+J()+")?",tt=new RegExp("^[0-9０-９٠-٩۰-۹]{2}$|^"+q+"$","i");function et(t){return t.length>=2&&tt.test(t)}function dt(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var d=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==d)return;var n,r,a=[],i=!0,o=!1;try{for(d=d.call(t);!(i=(n=d.next()).done)&&(a.push(n.value),!e||a.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{i||null==d.return||d.return()}finally{if(o)throw r}}return a}(t,e)||nt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function nt(t,e){if(t){if("string"==typeof t)return rt(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);return"Object"===d&&t.constructor&&(d=t.constructor.name),"Map"===d||"Set"===d?Array.from(t):"Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d)?rt(t,e):void 0}}function rt(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function at(t){var e=t.number,d=t.ext;if(!e)return"";if("+"!==e[0])throw new Error('"formatRFC3966()" expects "number" to be in E.164 format.');return"tel:".concat(e).concat(d?";ext="+d:"")}function it(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return ot(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return ot(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function ot(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function $t(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ut(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?$t(Object(d),!0).forEach((function(e){lt(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):$t(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function lt(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}var ct={formatExtension:function(t,e,d){return"".concat(t).concat(d.ext()).concat(e)}};function st(t,e,d,n){if(d=d?ut(ut({},ct),d):ct,n=new s(n),t.country&&"001"!==t.country){if(!n.hasCountry(t.country))throw new Error("Unknown country: ".concat(t.country));n.country(t.country)}else{if(!t.countryCallingCode)return t.phone||"";n.selectNumberingPlan(t.countryCallingCode)}var r,a=n.countryCallingCode(),i=d.v2?t.nationalNumber:t.phone;switch(e){case"NATIONAL":return i?gt(r=ft(i,t.carrierCode,"NATIONAL",n,d),t.ext,n,d.formatExtension):"";case"INTERNATIONAL":return i?(r=ft(i,null,"INTERNATIONAL",n,d),gt(r="+".concat(a," ").concat(r),t.ext,n,d.formatExtension)):"+".concat(a);case"E.164":return"+".concat(a).concat(i);case"RFC3966":return at({number:"+".concat(a).concat(i),ext:t.ext});case"IDD":if(!d.fromCountry)return;var o=function(t,e,d,n,r){if(C(n,r.metadata)===d){var a=ft(t,e,"NATIONAL",r);return"1"===d?d+" "+a:a}var i=function(t,e,d){var n=new s(d);return n.selectNumberingPlan(t,e),n.defaultIDDPrefix()?n.defaultIDDPrefix():Z.test(n.IDDPrefix())?n.IDDPrefix():void 0}(n,void 0,r.metadata);if(i)return"".concat(i," ").concat(d," ").concat(ft(t,null,"INTERNATIONAL",r))}(i,t.carrierCode,a,d.fromCountry,n);return gt(o,t.ext,n,d.formatExtension);default:throw new Error('Unknown "format" argument passed to "formatNumber()": "'.concat(e,'"'))}}function ft(t,e,d,n,r){var a=ht(n.formats(),t);return a?Y(t,a,{useInternationalFormat:"INTERNATIONAL"===d,withNationalPrefix:!a.nationalPrefixIsOptionalWhenFormattingInNationalFormat()||!r||!1!==r.nationalPrefix,carrierCode:e,metadata:n}):t}function ht(t,e){for(var d,n=it(t);!(d=n()).done;){var r=d.value;if(r.leadingDigitsPatterns().length>0){var a=r.leadingDigitsPatterns()[r.leadingDigitsPatterns().length-1];if(0!==e.search(a))continue}if(I(e,r.pattern()))return r}}function gt(t,e,d,n){return e?n(t,e,d):t}function yt(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function mt(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?yt(Object(d),!0).forEach((function(e){pt(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):yt(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function pt(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function bt(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var vt=function(){function t(e,d,n){if(function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),!e)throw new TypeError("First argument is required");if("string"!=typeof e)throw new TypeError("First argument must be a string");if("string"==typeof e){if("+"===e[0]&&!d)throw new TypeError("`metadata` argument not passed");if(a(d)&&a(d.countries)){n=d;var r=e;if(!Ct.test(r))throw new Error('Invalid `number` argument passed: must consist of a "+" followed by digits');var i=W(r,void 0,void 0,n);if(e=i.countryCallingCode,!(d=i.number))throw new Error("Invalid `number` argument passed: too short")}}if(!d)throw new TypeError("`nationalNumber` argument is required");if("string"!=typeof d)throw new TypeError("`nationalNumber` argument must be a string");p(n);var o=function(t,e){var d,n,r=new s(e);a=t,/^[A-Z]{2}$/.test(a)?(d=t,r.selectNumberingPlan(d),n=r.countryCallingCode()):n=t;var a;return{country:d,countryCallingCode:n}}(e,n),$=o.country,u=o.countryCallingCode;this.country=$,this.countryCallingCode=u,this.nationalNumber=d,this.number="+"+this.countryCallingCode+this.nationalNumber,this.getMetadata=function(){return n}}var e,d,n;return e=t,d=[{key:"setExt",value:function(t){this.ext=t}},{key:"getPossibleCountries",value:function(){return this.country?[this.country]:M(this.countryCallingCode,this.nationalNumber,this.getMetadata())}},{key:"isPossible",value:function(){return function(t,e,d){if(void 0===e&&(e={}),d=new s(d),e.v2){if(!t.countryCallingCode)throw new Error("Invalid phone number object passed");d.selectNumberingPlan(t.countryCallingCode)}else{if(!t.phone)return!1;if(t.country){if(!d.hasCountry(t.country))throw new Error("Unknown country: ".concat(t.country));d.country(t.country)}else{if(!t.countryCallingCode)throw new Error("Invalid phone number object passed");d.selectNumberingPlan(t.countryCallingCode)}}if(d.possibleLengths())return E(t.phone||t.nationalNumber,d);if(t.countryCallingCode&&d.isNonGeographicCallingCode(t.countryCallingCode))return!0;throw new Error('Missing "possibleLengths" in metadata. Perhaps the metadata has been generated before v1.0.18.')}(this,{v2:!0},this.getMetadata())}},{key:"isValid",value:function(){return function(t,e,d){return e=e||{},(d=new s(d)).selectNumberingPlan(t.country,t.countryCallingCode),d.hasTypes()?void 0!==k(t,e,d.metadata):I(e.v2?t.nationalNumber:t.phone,d.nationalNumberPattern())}(this,{v2:!0},this.getMetadata())}},{key:"isNonGeographic",value:function(){return new s(this.getMetadata()).isNonGeographicCallingCode(this.countryCallingCode)}},{key:"isEqual",value:function(t){return this.number===t.number&&this.ext===t.ext}},{key:"getType",value:function(){return k(this,{v2:!0},this.getMetadata())}},{key:"format",value:function(t,e){return st(this,t,e?mt(mt({},e),{},{v2:!0}):{v2:!0},this.getMetadata())}},{key:"formatNational",value:function(t){return this.format("NATIONAL",t)}},{key:"formatInternational",value:function(t){return this.format("INTERNATIONAL",t)}},{key:"getURI",value:function(t){return this.format("RFC3966",t)}}],d&&bt(e.prototype,d),n&&bt(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();var Ct=/^\+\d+$/;function Nt(t){return Nt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Nt(t)}function Pt(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function Ot(t,e){if(e&&("object"===Nt(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return xt(t)}function xt(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function wt(t){var e="function"==typeof Map?new Map:void 0;return wt=function(t){if(null===t||(d=t,-1===Function.toString.call(d).indexOf("[native code]")))return t;var d;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,n)}function n(){return St(t,arguments,At(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),It(n,t)},wt(t)}function St(t,e,d){return St=Et()?Reflect.construct:function(t,e,d){var n=[null];n.push.apply(n,e);var r=new(Function.bind.apply(t,n));return d&&It(r,d.prototype),r},St.apply(null,arguments)}function Et(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(t){return!1}}function It(t,e){return It=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t},It(t,e)}function At(t){return At=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)},At(t)}var Tt=function(t){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&It(t,e)}(o,t);var e,d,n,r,a,i=(e=o,d=Et(),function(){var t,n=At(e);if(d){var r=At(this).constructor;t=Reflect.construct(n,arguments,r)}else t=n.apply(this,arguments);return Ot(this,t)});function o(t){var e;return function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,o),e=i.call(this,t),Object.setPrototypeOf(xt(e),o.prototype),e.name=e.constructor.name,e}return n=o,r&&Pt(n.prototype,r),a&&Pt(n,a),Object.defineProperty(n,"prototype",{writable:!1}),n}(wt(Error)),jt=new RegExp("(?:"+J()+")$","i");function kt(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return Ft(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return Ft(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ft(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}var Mt={0:"0",1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9","０":"0","１":"1","２":"2","３":"3","４":"4","５":"5","６":"6","７":"7","８":"8","９":"9","٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","۰":"0","۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9"};function Dt(t){return Mt[t]}function Rt(t){for(var e,d="",n=kt(t.split(""));!(e=n()).done;){var r=Dt(e.value);r&&(d+=r)}return d}function _t(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return Lt(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return Lt(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Lt(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function Gt(t){for(var e,d="",n=_t(t.split(""));!(e=n()).done;){d+=Bt(e.value,d)||""}return d}function Bt(t,e,d){return"+"===t?e?void("function"==typeof d&&d("end")):"+":Dt(t)}function Ut(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return Ht(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return Ht(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Ht(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function Wt(t,e){var d=e.countries;e.defaultCountry;var n=e.metadata;n=new s(n);for(var r,a=Ut(d);!(r=a()).done;){var i=r.value;if(n.country(i),n.leadingDigits()){if(t&&0===t.search(n.leadingDigits()))return i}else if(k({phone:t,country:i},void 0,n.metadata))return i}}function Vt(t,e){var d=e.nationalNumber,n=e.defaultCountry,r=e.metadata,a=r.getCountryCodesForCallingCode(t);if(a)return 1===a.length?a[0]:Wt(d,{countries:a,defaultCountry:n,metadata:r.metadata})}var Kt=new RegExp("^\\+([0-9０-９٠-٩۰-۹]|[\\-\\.\\(\\)]?)*[0-9０-９٠-٩۰-۹]([0-9０-９٠-٩۰-۹]|[\\-\\.\\(\\)]?)*$","g"),Yt=new RegExp("^([0-9０-９٠-٩۰-۹]+((\\-)*[0-9０-９٠-٩۰-۹])*\\.)*[a-zA-Z]+((\\-)*[0-9０-９٠-٩۰-۹])*\\.?$","g"),Zt="tel:",Xt=";phone-context=";function Jt(t,e){var d,n=e.extractFormattedPhoneNumber,r=function(t){var e=t.indexOf(Xt);if(e<0)return null;var d=e+Xt.length;if(d>=t.length)return"";var n=t.indexOf(";",d);return n>=0?t.substring(d,n):t.substring(d)}(t);if(!function(t){return null===t||0!==t.length&&(Kt.test(t)||Yt.test(t))}(r))throw new Tt("NOT_A_NUMBER");if(null===r)d=n(t)||"";else{d="","+"===r.charAt(0)&&(d+=r);var a,i=t.indexOf(Zt);a=i>=0?i+Zt.length:0;var o=t.indexOf(Xt);d+=t.substring(a,o)}var $=d.indexOf(";isub=");if($>0&&(d=d.substring(0,$)),""!==d)return d}var Qt=new RegExp("[+＋0-9０-９٠-٩۰-۹]"),zt=new RegExp("[^0-9０-９٠-٩۰-۹#]+$");function qt(t,e,d){if(e=e||{},d=new s(d),e.defaultCountry&&!d.hasCountry(e.defaultCountry)){if(e.v2)throw new Tt("INVALID_COUNTRY");throw new Error("Unknown country: ".concat(e.defaultCountry))}var n=function(t,e,d){var n=Jt(t,{extractFormattedPhoneNumber:function(t){return function(t,e,d){if(!t)return;if(t.length>250){if(d)throw new Tt("TOO_LONG");return}if(!1===e)return t;var n=t.search(Qt);if(n<0)return;return t.slice(n).replace(zt,"")}(t,d,e)}});if(!n)return{};if(!et(n))return function(t){return z.test(t)}(n)?{error:"TOO_SHORT"}:{};var r=function(t){var e=t.search(jt);if(e<0)return{};for(var d=t.slice(0,e),n=t.match(jt),r=1;r<n.length;){if(n[r])return{number:d,ext:n[r]};r++}}(n);if(r.ext)return r;return{number:n}}(t,e.v2,e.extract),r=n.number,a=n.ext,i=n.error;if(!r){if(e.v2){if("TOO_SHORT"===i)throw new Tt("TOO_SHORT");throw new Tt("NOT_A_NUMBER")}return{}}var o=function(t,e,d,n){var r,a=W(Gt(t),e,d,n.metadata),i=a.countryCallingCodeSource,o=a.countryCallingCode,$=a.number;if(o)n.selectNumberingPlan(o);else{if(!$||!e&&!d)return{};n.selectNumberingPlan(e,d),e&&(r=e),o=d||C(e,n.metadata)}if(!$)return{countryCallingCodeSource:i,countryCallingCode:o};var u=U(Gt($),n),l=u.nationalNumber,c=u.carrierCode,s=Vt(o,{nationalNumber:l,defaultCountry:e,metadata:n});s&&(r=s,"001"===s||n.country(r));return{country:r,countryCallingCode:o,countryCallingCodeSource:i,nationalNumber:l,carrierCode:c}}(r,e.defaultCountry,e.defaultCallingCode,d),$=o.country,u=o.nationalNumber,l=o.countryCallingCode,c=o.countryCallingCodeSource,f=o.carrierCode;if(!d.hasSelectedNumberingPlan()){if(e.v2)throw new Tt("INVALID_COUNTRY");return{}}if(!u||u.length<2){if(e.v2)throw new Tt("TOO_SHORT");return{}}if(u.length>17){if(e.v2)throw new Tt("TOO_LONG");return{}}if(e.v2){var h=new vt(l,u,d.metadata);return $&&(h.country=$),f&&(h.carrierCode=f),a&&(h.ext=a),h.__countryCallingCodeSource=c,h}var g=!!(e.extended?d.hasSelectedNumberingPlan():$)&&I(u,d.nationalNumberPattern());return e.extended?{country:$,countryCallingCode:l,carrierCode:f,valid:g,possible:!!g||!(!0!==e.extended||!d.possibleLengths()||!E(u,d)),phone:u,ext:a}:g?function(t,e,d){var n={country:t,phone:e};d&&(n.ext=d);return n}($,u,a):{}}function te(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ee(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?te(Object(d),!0).forEach((function(e){de(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):te(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function de(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function ne(t,e,d){return qt(t,ee(ee({},e),{},{v2:!0}),d)}function re(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ae(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function ie(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var d=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==d)return;var n,r,a=[],i=!0,o=!1;try{for(d=d.call(t);!(i=(n=d.next()).done)&&(a.push(n.value),!e||a.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{i||null==d.return||d.return()}finally{if(o)throw r}}return a}(t,e)||function(t,e){if(!t)return;if("string"==typeof t)return oe(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return oe(t,e)}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function oe(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function $e(t){var e,d,n,r=ie(Array.prototype.slice.call(t),4),i=r[0],o=r[1],$=r[2],u=r[3];if("string"!=typeof i)throw new TypeError("A text for parsing must be a string.");if(e=i,o&&"string"!=typeof o){if(!a(o))throw new Error("Invalid second argument: ".concat(o));$?(d=o,n=$):n=o}else u?(d=$,n=u):(d=void 0,n=$),o&&(d=function(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?re(Object(d),!0).forEach((function(e){ae(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):re(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}({defaultCountry:o},d));return{text:e,options:d,metadata:n}}function ue(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata;return ne(e,d,n)}function le(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ce(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?le(Object(d),!0).forEach((function(e){se(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):le(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function se(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function fe(t,e,d){e&&e.defaultCountry&&!N(e.defaultCountry,d)&&(e=ce(ce({},e),{},{defaultCountry:void 0}));try{return ne(t,e,d)}catch(t){if(!(t instanceof Tt))throw t}}function he(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata;return fe(e,d,n)}function ge(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ye(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?ge(Object(d),!0).forEach((function(e){me(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):ge(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function me(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function pe(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=fe(e,d=ye(ye({},d),{},{extract:!1}),n);return r&&r.isValid()||!1}function be(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function ve(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?be(Object(d),!0).forEach((function(e){Ce(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):be(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function Ce(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function Ne(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=fe(e,d=ve(ve({},d),{},{extract:!1}),n);return r&&r.isPossible()||!1}function Pe(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function Oe(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?Pe(Object(d),!0).forEach((function(e){xe(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):Pe(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function xe(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function we(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata;d=Oe(Oe({},d),{},{extract:!1});try{var r=ne(e,d,n);(n=new s(n)).selectNumberingPlan(r.countryCallingCode);var a=w(r.nationalNumber,n);if("IS_POSSIBLE"!==a)return a}catch(t){if(t instanceof Tt)return t.message;throw t}}function Se(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function Ee(t,e,d){return e&&Se(t.prototype,e),d&&Se(t,d),Object.defineProperty(t,"prototype",{writable:!1}),t}function Ie(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var Ae=Ee((function t(e,d){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null;Ie(this,t),this.key=e,this.value=d,this.next=n,this.prev=r})),Te=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:10;Ie(this,t),this.size=0,this.limit=e,this.head=null,this.tail=null,this.cache={}}return Ee(t,[{key:"put",value:function(t,e){if(this.ensureLimit(),this.head){var d=new Ae(t,e,this.head);this.head.prev=d,this.head=d}else this.head=this.tail=new Ae(t,e);this.cache[t]=this.head,this.size++}},{key:"get",value:function(t){if(this.cache[t]){var e=this.cache[t].value;return this.remove(t),this.put(t,e),e}console.log("Item not available in cache for key ".concat(t))}},{key:"ensureLimit",value:function(){this.size===this.limit&&this.remove(this.tail.key)}},{key:"remove",value:function(t){var e=this.cache[t];null!==e.prev?e.prev.next=e.next:this.head=e.next,null!==e.next?e.next.prev=e.prev:this.tail=e.prev,delete this.cache[t],this.size--}},{key:"clear",value:function(){this.head=null,this.tail=null,this.size=0,this.cache={}}}]),t}();function je(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var ke=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.cache=new Te(e)}var e,d,n;return e=t,(d=[{key:"getPatternForRegExp",value:function(t){var e=this.cache.get(t);return e||(e=new RegExp("^"+t),this.cache.put(t,e)),e}}])&&je(e.prototype,d),n&&je(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function Fe(t,e){if(t<0||e<=0||e<t)throw new TypeError;return"{".concat(t,",").concat(e,"}")}function Me(t,e){var d=e.search(t);return d>=0?e.slice(0,d):e}var De="   ᠎ - \u2028\u2029  　",Re="[".concat(De,"]"),_e="[^".concat(De,"]"),Le="[".concat("0-9٠-٩۰-۹߀-߉०-९০-৯੦-੯૦-૯୦-୯௦-௯౦-౯೦-೯൦-൯๐-๙໐-໙༠-༩၀-၉႐-႙០-៩᠐-᠙᥆-᥏᧐-᧙᪀-᪉᪐-᪙᭐-᭙᮰-᮹᱀-᱉᱐-᱙꘠-꘩꣐-꣙꤀-꤉꧐-꧙꩐-꩙꯰-꯹０-９","]"),Ge="A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԧԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠࢢ-ࢬऄ-हऽॐक़-ॡॱ-ॷॹ-ॿঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚗꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞓꞠ-Ɦꟸ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꪀ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ﬀ-ﬆﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼＡ-Ｚａ-ｚｦ-ﾾￂ-ￇￊ-ￏￒ-ￗￚ-ￜ",Be="[".concat(Ge,"]"),Ue=new RegExp(Be),He="[".concat("$¢-¥֏؋৲৳৻૱௹฿៛₠-₹꠸﷼﹩＄￠￡￥￦","]"),We=new RegExp(He),Ve="[".concat("̀-ͯ҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ࣾऀ-ंऺ़ु-ै्॑-ॗॢॣঁ়ু-ৄ্ৢৣਁਂ਼ੁੂੇੈੋ-੍ੑੰੱੵઁં઼ુ-ૅેૈ્ૢૣଁ଼ିୁ-ୄ୍ୖୢୣஂீ்ా-ీె-ైొ-్ౕౖౢౣ಼ಿೆೌ್ೢೣു-ൄ്ൢൣ්ි-ුූัิ-ฺ็-๎ັິ-ູົຼ່-ໍཱ༹༘༙༵༷-ཾྀ-྄྆྇ྍ-ྗྙ-ྼ࿆ိ-ူဲ-့္်ွှၘၙၞ-ၠၱ-ၴႂႅႆႍႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴឵ិ-ួំ៉-៓៝᠋-᠍ᢩᤠ-ᤢᤧᤨᤲ᤹-᤻ᨘᨗᩖᩘ-ᩞ᩠ᩢᩥ-ᩬᩳ-᩿᩼ᬀ-ᬃ᬴ᬶ-ᬺᬼᭂ᭫-᭳ᮀᮁᮢ-ᮥᮨᮩ᯦᮫ᯨᯩᯭᯯ-ᯱᰬ-ᰳᰶ᰷᳐-᳔᳒-᳢᳠-᳨᳭᳴᷀-ᷦ᷼-᷿⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〭꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠥꠦ꣄꣠-꣱ꤦ-꤭ꥇ-ꥑꦀ-ꦂ꦳ꦶ-ꦹꦼꨩ-ꨮꨱꨲꨵꨶꩃꩌꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫬꫭ꫶ꯥꯨ꯭ﬞ︀-️︠-︦","]"),Ke=new RegExp(Ve),Ye=new RegExp("[\0--ÿĀ-ſḀ-ỿƀ-ɏ̀-ͯ]");function Ze(t){return!(!Ue.test(t)&&!Ke.test(t))&&Ye.test(t)}function Xe(t){return"%"===t||We.test(t)}function Je(t,e,d){var n=!0,r=he(t,d);if(r||(n=!1,r=he(t,{defaultCallingCode:e.countryCallingCode},d)),!r)return"INVALID_NUMBER";if(e.ext){if(r.ext!==e.ext)return"NO_MATCH"}else if(r.ext)return"NO_MATCH";return n&&e.countryCallingCode!==r.countryCallingCode?"NO_MATCH":e.number===r.number?n?"EXACT_MATCH":"NSN_MATCH":0===e.nationalNumber.indexOf(r.nationalNumber)||0===r.nationalNumber.indexOf(e.nationalNumber)?"SHORT_NSN_MATCH":"NO_MATCH"}var Qe={POSSIBLE:function(t,e){return e.candidate,e.metadata,!0},VALID:function(t,e){var d=e.candidate;e.defaultCountry;var n=e.metadata;return!(!t.isValid()||!ze(t,d,n))},STRICT_GROUPING:function(t,e){var d=e.candidate,n=e.defaultCountry,r=e.metadata;return e.regExpCache,!(!t.isValid()||!ze(t,d,r)||td(t,d)||!qe(t,{defaultCountry:n,metadata:r}))&&ed()},EXACT_GROUPING:function(t,e){var d=e.candidate,n=e.defaultCountry,r=e.metadata;return e.regExpCache,!(!t.isValid()||!ze(t,d,r)||td(t,d)||!qe(t,{defaultCountry:n,metadata:r}))&&ed()}};function ze(t,e,d){for(var n=0;n<e.length-1;n++){var r=e.charAt(n);if("x"===r||"X"===r){var a=e.charAt(n+1);if("x"===a||"X"===a){if(n++,"NSN_MATCH"!==Je(e.substring(n),t,d))return!1}else{var i=Rt(e.substring(n));if(i){if(t.ext!==i)return!1}else if(t.ext)return!1}}}return!0}function qe(t,e){var d=e.defaultCountry,n=e.metadata;if("FROM_DEFAULT_COUNTRY"!==t.__countryCallingCodeSource)return!0;var r=new s(n);r.selectNumberingPlan(t.countryCallingCode),t.country||Vt(t.countryCallingCode,{nationalNumber:t.nationalNumber,defaultCountry:d,metadata:r});var a=t.nationalNumber,i=ht(r.numberingPlan.formats(),a);return!i.nationalPrefixFormattingRule()||(!!r.numberingPlan.nationalPrefixIsOptionalWhenFormattingInNationalFormat()||(!i.usesNationalPrefix()||Boolean(t.nationalPrefix)))}function td(t,e){var d=e.indexOf("/");if(d<0)return!1;var n=e.indexOf("/",d+1);return!(n<0)&&(!("FROM_NUMBER_WITH_PLUS_SIGN"===t.__countryCallingCodeSource||"FROM_NUMBER_WITHOUT_PLUS_SIGN"===t.__countryCallingCodeSource)||Rt(e.substring(0,d))!==t.countryCallingCode||e.slice(n+1).indexOf("/")>=0)}function ed(t,e,d,n,r){throw new Error("This part of code hasn't been ported")}var dd=/[\\/] *x/;function nd(t){return Me(dd,t)}var rd=/(?:(?:[0-3]?\d\/[01]?\d)|(?:[01]?\d\/[0-3]?\d))\/(?:[12]\d)?\d{2}/,ad=/[12]\d{3}[-/]?[01]\d[-/]?[0-3]\d +[0-2]\d$/,id=/^:[0-5]\d/;function od(t,e,d){if(rd.test(t))return!1;if(ad.test(t)){var n=d.slice(e+t.length);if(id.test(n))return!1}return!0}var $d="(\\[（［",ud=")\\]）］",ld="[^".concat($d).concat(ud,"]"),cd="[".concat($d).concat(_,"]"),sd=new RegExp("^"+cd),fd=Fe(0,3),hd=new RegExp("^(?:[(\\[（［])?(?:"+ld+"+["+")\\]）］])?"+ld+"+(?:["+"(\\[（［]"+ld+"+["+")\\]）］])"+fd+ld+"*$"),gd=/\d{1,5}-+\d{1,5}\s{0,4}\(\d{1,4}/;function yd(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return md(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return md(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function md(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function pd(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function bd(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var vd=J(),Cd=["\\/+(.*)/","(\\([^(]*)","(?:".concat(Re,"-|-").concat(Re,")").concat(Re,"*(.+)"),"[‒-―－]".concat(Re,"*(.+)"),"\\.+".concat(Re,"*([^.]+)"),"".concat(Re,"+(").concat(_e,"+)")],Nd=Fe(0,2),Pd=Fe(0,4),Od=Fe(0,20),xd="[".concat(R,"]")+Pd,wd=Le+Fe(1,20),Sd="(?:"+cd+xd+")"+Nd+wd+"(?:"+xd+wd+")"+Od+"(?:"+vd+")?",Ed=new RegExp("[^".concat("0-9²³¹¼-¾٠-٩۰-۹߀-߉०-९০-৯৴-৹੦-੯૦-૯୦-୯୲-୷௦-௲౦-౯౸-౾೦-೯൦-൵๐-๙໐-໙༠-༳၀-၉႐-႙፩-፼ᛮ-ᛰ០-៩៰-៹᠐-᠙᥆-᥏᧐-᧚᪀-᪉᪐-᪙᭐-᭙᮰-᮹᱀-᱉᱐-᱙⁰⁴-⁹₀-₉⅐-ↂↅ-↉①-⒛⓪-⓿❶-➓⳽〇〡-〩〸-〺㆒-㆕㈠-㈩㉈-㉏㉑-㉟㊀-㊉㊱-㊿꘠-꘩ꛦ-ꛯ꠰-꠵꣐-꣙꤀-꤉꧐-꧙꩐-꩙꯰-꯹０-９").concat(Ge,"#]+$")),Id=Number.MAX_SAFE_INTEGER||Math.pow(2,53)-1,Ad=function(){function t(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",d=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0;if(pd(this,t),!(d={v2:d.v2,defaultCallingCode:d.defaultCallingCode,defaultCountry:d.defaultCountry&&N(d.defaultCountry,n)?d.defaultCountry:void 0,leniency:d.leniency||(d.extended?"POSSIBLE":"VALID"),maxTries:d.maxTries||Id}).leniency)throw new TypeError("`leniency` is required");if("POSSIBLE"!==d.leniency&&"VALID"!==d.leniency)throw new TypeError('Invalid `leniency`: "'.concat(d.leniency,'". Supported values: "POSSIBLE", "VALID".'));if(d.maxTries<0)throw new TypeError("`maxTries` must be `>= 0`");if(this.text=e,this.options=d,this.metadata=n,this.leniency=Qe[d.leniency],!this.leniency)throw new TypeError('Unknown leniency: "'.concat(d.leniency,'"'));this.maxTries=d.maxTries,this.PATTERN=new RegExp(Sd,"ig"),this.state="NOT_READY",this.searchIndex=0,this.regExpCache=new ke(32)}var e,d,n;return e=t,d=[{key:"find",value:function(){for(var t;this.maxTries>0&&null!==(t=this.PATTERN.exec(this.text));){var e=t[0],d=t.index;if(od(e=nd(e),d,this.text)){var n=this.parseAndVerify(e,d,this.text)||this.extractInnerMatch(e,d,this.text);if(n){if(this.options.v2)return{startsAt:n.startsAt,endsAt:n.endsAt,number:n.phoneNumber};var r=n.phoneNumber,a={startsAt:n.startsAt,endsAt:n.endsAt,phone:r.nationalNumber};return r.country?a.country=r.country:a.countryCallingCode=r.countryCallingCode,r.ext&&(a.ext=r.ext),a}}this.maxTries--}}},{key:"extractInnerMatch",value:function(t,e,d){for(var n,r=yd(Cd);!(n=r()).done;)for(var a=n.value,i=!0,o=void 0,$=new RegExp(a,"g");this.maxTries>0&&null!==(o=$.exec(t));){if(i){var u=Me(Ed,t.slice(0,o.index)),l=this.parseAndVerify(u,e,d);if(l)return l;this.maxTries--,i=!1}var c=Me(Ed,o[1]),s=t.indexOf(c,o.index),f=this.parseAndVerify(c,e+s,d);if(f)return f;this.maxTries--}}},{key:"parseAndVerify",value:function(t,e,d){if(function(t,e,d,n){if(hd.test(t)&&!gd.test(t)){if("POSSIBLE"!==n){if(e>0&&!sd.test(t)){var r=d[e-1];if(Xe(r)||Ze(r))return!1}var a=e+t.length;if(a<d.length){var i=d[a];if(Xe(i)||Ze(i))return!1}}return!0}}(t,e,d,this.options.leniency)){var n=he(t,{extended:!0,defaultCountry:this.options.defaultCountry,defaultCallingCode:this.options.defaultCallingCode},this.metadata);if(n&&n.isPossible())return this.leniency(n,{candidate:t,defaultCountry:this.options.defaultCountry,metadata:this.metadata,regExpCache:this.regExpCache})?{startsAt:e,endsAt:e+t.length,phoneNumber:n}:void 0}}},{key:"hasNext",value:function(){return"NOT_READY"===this.state&&(this.lastMatch=this.find(),this.lastMatch?this.state="READY":this.state="DONE"),"READY"===this.state}},{key:"next",value:function(){if(!this.hasNext())throw new Error("No next element");var t=this.lastMatch;return this.lastMatch=null,this.state="NOT_READY",t}}],d&&bd(e.prototype,d),n&&bd(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function Td(){for(var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=new Ad(e,d,n),a=[];r.hasNext();)a.push(r.next());return a}function jd(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function kd(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=new Ad(e,d,n);return jd({},Symbol.iterator,(function(){return{next:function(){return r.hasNext()?{done:!1,value:r.next()}:{done:!0}}}}))}function Fd(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function Md(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?Fd(Object(d),!0).forEach((function(e){Dd(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):Fd(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function Dd(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function Rd(){for(var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=new Ad(e,Md(Md({},d),{},{v2:!0}),n),a=[];r.hasNext();)a.push(r.next());return a}function _d(t,e){var d=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),d.push.apply(d,n)}return d}function Ld(t){for(var e=1;e<arguments.length;e++){var d=null!=arguments[e]?arguments[e]:{};e%2?_d(Object(d),!0).forEach((function(e){Gd(t,e,d[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(d)):_d(Object(d)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(d,e))}))}return t}function Gd(t,e,d){return e in t?Object.defineProperty(t,e,{value:d,enumerable:!0,configurable:!0,writable:!0}):t[e]=d,t}function Bd(){var t=$e(arguments),e=t.text,d=t.options,n=t.metadata,r=new Ad(e,Ld(Ld({},d),{},{v2:!0}),n);return Gd({},Symbol.iterator,(function(){return{next:function(){return r.hasNext()?{done:!1,value:r.next()}:{done:!0}}}}))}function Ud(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var Hd=function(){function t(e){var d=e.onCountryChange,n=e.onCallingCodeChange;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.onCountryChange=d,this.onCallingCodeChange=n}var e,d,n;return e=t,(d=[{key:"reset",value:function(t){var e=t.country,d=t.callingCode;this.international=!1,this.missingPlus=!1,this.IDDPrefix=void 0,this.callingCode=void 0,this.digits="",this.resetNationalSignificantNumber(),this.initCountryAndCallingCode(e,d)}},{key:"resetNationalSignificantNumber",value:function(){this.nationalSignificantNumber=this.getNationalDigits(),this.nationalSignificantNumberMatchesInput=!0,this.nationalPrefix=void 0,this.carrierCode=void 0,this.complexPrefixBeforeNationalSignificantNumber=void 0}},{key:"update",value:function(t){for(var e=0,d=Object.keys(t);e<d.length;e++){var n=d[e];this[n]=t[n]}}},{key:"initCountryAndCallingCode",value:function(t,e){this.setCountry(t),this.setCallingCode(e)}},{key:"setCountry",value:function(t){this.country=t,this.onCountryChange(t)}},{key:"setCallingCode",value:function(t){this.callingCode=t,this.onCallingCodeChange(t,this.country)}},{key:"startInternationalNumber",value:function(t,e){this.international=!0,this.initCountryAndCallingCode(t,e)}},{key:"appendDigits",value:function(t){this.digits+=t}},{key:"appendNationalSignificantNumberDigits",value:function(t){this.nationalSignificantNumber+=t}},{key:"getNationalDigits",value:function(){return this.international?this.digits.slice((this.IDDPrefix?this.IDDPrefix.length:0)+(this.callingCode?this.callingCode.length:0)):this.digits}},{key:"getDigitsWithoutInternationalPrefix",value:function(){return this.international&&this.IDDPrefix?this.digits.slice(this.IDDPrefix.length):this.digits}}])&&Ud(e.prototype,d),n&&Ud(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function Wd(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return Vd(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return Vd(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function Vd(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}var Kd="x",Yd=new RegExp(Kd);function Zd(t,e){if(e<1)return"";for(var d="";e>1;)1&e&&(d+=t),e>>=1,t+=t;return d+t}function Xd(t,e){return")"===t[e]&&e++,function(t){var e=[],d=0;for(;d<t.length;)"("===t[d]?e.push(d):")"===t[d]&&e.pop(),d++;var n=0,r="";e.push(t.length);for(var a=0,i=e;a<i.length;a++){var o=i[a];r+=t.slice(n,o),n=o+1}return r}(t.slice(0,e))}function Jd(t,e,d){var n=d.metadata,r=d.shouldTryNationalPrefixFormattingRule,a=d.getSeparatorAfterNationalPrefix;if(new RegExp("^(?:".concat(e.pattern(),")$")).test(t.nationalSignificantNumber))return function(t,e,d){var n=d.metadata,r=d.shouldTryNationalPrefixFormattingRule,a=d.getSeparatorAfterNationalPrefix;if(t.nationalSignificantNumber,t.international,t.nationalPrefix,t.carrierCode,r(e)){var i=Qd(t,e,{useNationalPrefixFormattingRule:!0,getSeparatorAfterNationalPrefix:a,metadata:n});if(i)return i}return Qd(t,e,{useNationalPrefixFormattingRule:!1,getSeparatorAfterNationalPrefix:a,metadata:n})}(t,e,{metadata:n,shouldTryNationalPrefixFormattingRule:r,getSeparatorAfterNationalPrefix:a})}function Qd(t,e,d){var n=d.metadata,r=d.useNationalPrefixFormattingRule,a=d.getSeparatorAfterNationalPrefix,i=Y(t.nationalSignificantNumber,e,{carrierCode:t.carrierCode,useInternationalFormat:t.international,withNationalPrefix:r,metadata:n});if(r||(t.nationalPrefix?i=t.nationalPrefix+a(e)+i:t.complexPrefixBeforeNationalSignificantNumber&&(i=t.complexPrefixBeforeNationalSignificantNumber+" "+i)),function(t,e){return Rt(t)===e.getNationalDigits()}(i,t))return i}function zd(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var qd=function(){function t(){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t)}var e,d,n;return e=t,(d=[{key:"parse",value:function(t){if(this.context=[{or:!0,instructions:[]}],this.parsePattern(t),1!==this.context.length)throw new Error("Non-finalized contexts left when pattern parse ended");var e=this.context[0],d=e.branches,n=e.instructions;if(d)return{op:"|",args:d.concat([nn(n)])};if(0===n.length)throw new Error("Pattern is required");return 1===n.length?n[0]:n}},{key:"startContext",value:function(t){this.context.push(t)}},{key:"endContext",value:function(){this.context.pop()}},{key:"getContext",value:function(){return this.context[this.context.length-1]}},{key:"parsePattern",value:function(t){if(!t)throw new Error("Pattern is required");var e=t.match(dn);if(e){var d=e[1],n=t.slice(0,e.index),r=t.slice(e.index+d.length);switch(d){case"(?:":n&&this.parsePattern(n),this.startContext({or:!0,instructions:[],branches:[]});break;case")":if(!this.getContext().or)throw new Error('")" operator must be preceded by "(?:" operator');if(n&&this.parsePattern(n),0===this.getContext().instructions.length)throw new Error('No instructions found after "|" operator in an "or" group');var a=this.getContext().branches;a.push(nn(this.getContext().instructions)),this.endContext(),this.getContext().instructions.push({op:"|",args:a});break;case"|":if(!this.getContext().or)throw new Error('"|" operator can only be used inside "or" groups');if(n&&this.parsePattern(n),!this.getContext().branches){if(1!==this.context.length)throw new Error('"branches" not found in an "or" group context');this.getContext().branches=[]}this.getContext().branches.push(nn(this.getContext().instructions)),this.getContext().instructions=[];break;case"[":n&&this.parsePattern(n),this.startContext({oneOfSet:!0});break;case"]":if(!this.getContext().oneOfSet)throw new Error('"]" operator must be preceded by "[" operator');this.endContext(),this.getContext().instructions.push({op:"[]",args:tn(n)});break;default:throw new Error("Unknown operator: ".concat(d))}r&&this.parsePattern(r)}else{if(en.test(t))throw new Error("Illegal characters found in a pattern: ".concat(t));this.getContext().instructions=this.getContext().instructions.concat(t.split(""))}}}])&&zd(e.prototype,d),n&&zd(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function tn(t){for(var e=[],d=0;d<t.length;){if("-"===t[d]){if(0===d||d===t.length-1)throw new Error("Couldn't parse a one-of set pattern: ".concat(t));for(var n=t[d-1].charCodeAt(0)+1,r=t[d+1].charCodeAt(0)-1,a=n;a<=r;)e.push(String.fromCharCode(a)),a++}else e.push(t[d]);d++}return e}var en=/[\(\)\[\]\?\:\|]/,dn=new RegExp("(\\||\\(\\?\\:|\\)|\\[|\\])");function nn(t){return 1===t.length?t[0]:t}function rn(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return an(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return an(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function an(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function on(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var $n=function(){function t(e){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.matchTree=(new qd).parse(e)}var e,d,n;return e=t,d=[{key:"match",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},d=e.allowOverflow;if(!t)throw new Error("String is required");var n=un(t.split(""),this.matchTree,!0);if(n&&n.match&&delete n.matchedChars,!n||!n.overflow||d)return n}}],d&&on(e.prototype,d),n&&on(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function un(t,e,d){if("string"==typeof e){var n=t.join("");return 0===e.indexOf(n)?t.length===e.length?{match:!0,matchedChars:t}:{partialMatch:!0}:0===n.indexOf(e)?d&&t.length>e.length?{overflow:!0}:{match:!0,matchedChars:t.slice(0,e.length)}:void 0}if(Array.isArray(e)){for(var r=t.slice(),a=0;a<e.length;){var i=un(r,e[a],d&&a===e.length-1);if(!i)return;if(i.overflow)return i;if(!i.match){if(i.partialMatch)return{partialMatch:!0};throw new Error("Unsupported match result:\n".concat(JSON.stringify(i,null,2)))}if(0===(r=r.slice(i.matchedChars.length)).length)return a===e.length-1?{match:!0,matchedChars:t}:{partialMatch:!0};a++}return d?{overflow:!0}:{match:!0,matchedChars:t.slice(0,t.length-r.length)}}switch(e.op){case"|":for(var o,$,u=rn(e.args);!($=u()).done;){var l=un(t,$.value,d);if(l){if(l.overflow)return l;if(l.match)return{match:!0,matchedChars:l.matchedChars};if(!l.partialMatch)throw new Error("Unsupported match result:\n".concat(JSON.stringify(l,null,2)));o=!0}}return o?{partialMatch:!0}:void 0;case"[]":for(var c,s=rn(e.args);!(c=s()).done;){var f=c.value;if(t[0]===f)return 1===t.length?{match:!0,matchedChars:t}:d?{overflow:!0}:{match:!0,matchedChars:[f]}}return;default:throw new Error("Unsupported instruction tree: ".concat(e))}}function ln(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=function(t,e){if(!t)return;if("string"==typeof t)return cn(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return cn(t,e)}(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function cn(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function sn(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var fn=Zd("9",15),hn=/[- ]/,gn=new RegExp("["+R+"]*\\$1["+R+"]*(\\$\\d["+R+"]*)*$"),yn=function(){function t(e){e.state;var d=e.metadata;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.metadata=d,this.resetFormat()}var e,d,n;return e=t,d=[{key:"resetFormat",value:function(){this.chosenFormat=void 0,this.template=void 0,this.nationalNumberTemplate=void 0,this.populatedNationalNumberTemplate=void 0,this.populatedNationalNumberTemplatePosition=-1}},{key:"reset",value:function(t,e){this.resetFormat(),t?(this.isNANP="1"===t.callingCode(),this.matchingFormats=t.formats(),e.nationalSignificantNumber&&this.narrowDownMatchingFormats(e)):(this.isNANP=void 0,this.matchingFormats=[])}},{key:"format",value:function(t,e){var d=this;if(function(t,e){return"IS_POSSIBLE"===w(t,e)}(e.nationalSignificantNumber,this.metadata))for(var n,r=ln(this.matchingFormats);!(n=r()).done;){var a=n.value,i=Jd(e,a,{metadata:this.metadata,shouldTryNationalPrefixFormattingRule:function(t){return d.shouldTryNationalPrefixFormattingRule(t,{international:e.international,nationalPrefix:e.nationalPrefix})},getSeparatorAfterNationalPrefix:function(t){return d.getSeparatorAfterNationalPrefix(t)}});if(i)return this.resetFormat(),this.chosenFormat=a,this.setNationalNumberTemplate(i.replace(/\d/g,Kd),e),this.populatedNationalNumberTemplate=i,this.populatedNationalNumberTemplatePosition=this.template.lastIndexOf(Kd),i}return this.formatNationalNumberWithNextDigits(t,e)}},{key:"formatNationalNumberWithNextDigits",value:function(t,e){var d=this.chosenFormat,n=this.chooseFormat(e);if(n)return n===d?this.formatNextNationalNumberDigits(t):this.formatNextNationalNumberDigits(e.getNationalDigits())}},{key:"narrowDownMatchingFormats",value:function(t){var e=this,d=t.nationalSignificantNumber,n=t.nationalPrefix,r=t.international,a=d,i=a.length-3;i<0&&(i=0),this.matchingFormats=this.matchingFormats.filter((function(t){return e.formatSuits(t,r,n)&&e.formatMatches(t,a,i)})),this.chosenFormat&&-1===this.matchingFormats.indexOf(this.chosenFormat)&&this.resetFormat()}},{key:"formatSuits",value:function(t,e,d){return!(d&&!t.usesNationalPrefix()&&!t.nationalPrefixIsOptionalWhenFormattingInNationalFormat()||!e&&!d&&t.nationalPrefixIsMandatoryWhenFormattingInNationalFormat())}},{key:"formatMatches",value:function(t,e,d){var n=t.leadingDigitsPatterns().length;if(0===n)return!0;d=Math.min(d,n-1);var r=t.leadingDigitsPatterns()[d];if(e.length<3)try{return void 0!==new $n(r).match(e,{allowOverflow:!0})}catch(t){return console.error(t),!0}return new RegExp("^(".concat(r,")")).test(e)}},{key:"getFormatFormat",value:function(t,e){return e?t.internationalFormat():t.format()}},{key:"chooseFormat",value:function(t){for(var e,d=this,n=function(){var n=e.value;return d.chosenFormat===n?"break":gn.test(d.getFormatFormat(n,t.international))?d.createTemplateForFormat(n,t)?(d.chosenFormat=n,"break"):(d.matchingFormats=d.matchingFormats.filter((function(t){return t!==n})),"continue"):"continue"},r=ln(this.matchingFormats.slice());!(e=r()).done;){var a=n();if("break"===a)break}return this.chosenFormat||this.resetFormat(),this.chosenFormat}},{key:"createTemplateForFormat",value:function(t,e){if(!(t.pattern().indexOf("|")>=0)){var d=this.getTemplateForFormat(t,e);return d?(this.setNationalNumberTemplate(d,e),!0):void 0}}},{key:"getSeparatorAfterNationalPrefix",value:function(t){return this.isNANP||t&&t.nationalPrefixFormattingRule()&&hn.test(t.nationalPrefixFormattingRule())?" ":""}},{key:"getInternationalPrefixBeforeCountryCallingCode",value:function(t,e){var d=t.IDDPrefix,n=t.missingPlus;return d?e&&!1===e.spacing?d:d+" ":n?"":"+"}},{key:"getTemplate",value:function(t){if(this.template){for(var e=-1,d=0,n=t.international?this.getInternationalPrefixBeforeCountryCallingCode(t,{spacing:!1}):"";d<n.length+t.getDigitsWithoutInternationalPrefix().length;)e=this.template.indexOf(Kd,e+1),d++;return Xd(this.template,e+1)}}},{key:"setNationalNumberTemplate",value:function(t,e){this.nationalNumberTemplate=t,this.populatedNationalNumberTemplate=t,this.populatedNationalNumberTemplatePosition=-1,e.international?this.template=this.getInternationalPrefixBeforeCountryCallingCode(e).replace(/[\d\+]/g,Kd)+Zd(Kd,e.callingCode.length)+" "+t:this.template=t}},{key:"getTemplateForFormat",value:function(t,e){var d=e.nationalSignificantNumber,n=e.international,r=e.nationalPrefix,a=e.complexPrefixBeforeNationalSignificantNumber,i=t.pattern();i=i.replace(/\[([^\[\]])*\]/g,"\\d").replace(/\d(?=[^,}][^,}])/g,"\\d");var o=fn.match(i)[0];if(!(d.length>o.length)){var $=new RegExp("^"+i+"$"),u=d.replace(/\d/g,"9");$.test(u)&&(o=u);var l,c=this.getFormatFormat(t,n);if(this.shouldTryNationalPrefixFormattingRule(t,{international:n,nationalPrefix:r})){var s=c.replace(K,t.nationalPrefixFormattingRule());if(Rt(t.nationalPrefixFormattingRule())===(r||"")+Rt("$1")&&(c=s,l=!0,r))for(var f=r.length;f>0;)c=c.replace(/\d/,Kd),f--}var h=o.replace(new RegExp(i),c).replace(new RegExp("9","g"),Kd);return l||(a?h=Zd(Kd,a.length)+" "+h:r&&(h=Zd(Kd,r.length)+this.getSeparatorAfterNationalPrefix(t)+h)),n&&(h=V(h)),h}}},{key:"formatNextNationalNumberDigits",value:function(t){var e=function(t,e,d){for(var n,r=Wd(d.split(""));!(n=r()).done;){var a=n.value;if(t.slice(e+1).search(Yd)<0)return;e=t.search(Yd),t=t.replace(Yd,a)}return[t,e]}(this.populatedNationalNumberTemplate,this.populatedNationalNumberTemplatePosition,t);if(e)return this.populatedNationalNumberTemplate=e[0],this.populatedNationalNumberTemplatePosition=e[1],Xd(this.populatedNationalNumberTemplate,this.populatedNationalNumberTemplatePosition+1);this.resetFormat()}},{key:"shouldTryNationalPrefixFormattingRule",value:function(t,e){var d=e.international,n=e.nationalPrefix;if(t.nationalPrefixFormattingRule()){var r=t.usesNationalPrefix();if(r&&n||!r&&!d)return!0}}}],d&&sn(e.prototype,d),n&&sn(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function mn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var d=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==d)return;var n,r,a=[],i=!0,o=!1;try{for(d=d.call(t);!(i=(n=d.next()).done)&&(a.push(n.value),!e||a.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{i||null==d.return||d.return()}finally{if(o)throw r}}return a}(t,e)||function(t,e){if(!t)return;if("string"==typeof t)return pn(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return pn(t,e)}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function pn(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function bn(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var vn=new RegExp("^"+("["+R+"0-9０-９٠-٩۰-۹]+")+"$","i"),Cn="(?:[+＋]["+R+"0-9０-９٠-٩۰-۹]*|["+R+"0-9０-９٠-٩۰-۹]+)",Nn=new RegExp("[^"+R+"0-9０-９٠-٩۰-۹]+.*$"),Pn=/[^\d\[\]]/,On=function(){function t(e){var d=e.defaultCountry,n=e.defaultCallingCode,r=e.metadata,a=e.onNationalSignificantNumberChange;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.defaultCountry=d,this.defaultCallingCode=n,this.metadata=r,this.onNationalSignificantNumberChange=a}var e,d,n;return e=t,(d=[{key:"input",value:function(t,e){var d,n=function(t){var e=mn(function(t){var e=function(t){var e,d=t.search(Cn);if(!(d<0))return"+"===(t=t.slice(d))[0]&&(e=!0,t=t.slice("+".length)),t=t.replace(Nn,""),e&&(t="+"+t),t}(t)||"";return"+"===e[0]?[e.slice("+".length),!0]:[e]}(t),2),d=e[0],n=e[1];return vn.test(d)||(d=""),[d,n]}(t),r=mn(n,2),a=r[0],i=r[1],o=Rt(a);return i&&(e.digits||(e.startInternationalNumber(),o||(d=!0))),o&&this.inputDigits(o,e),{digits:o,justLeadingPlus:d}}},{key:"inputDigits",value:function(t,e){var d=e.digits,n=d.length<3&&d.length+t.length>=3;if(e.appendDigits(t),n&&this.extractIddPrefix(e),this.isWaitingForCountryCallingCode(e)){if(!this.extractCountryCallingCode(e))return}else e.appendNationalSignificantNumberDigits(t);e.international||this.hasExtractedNationalSignificantNumber||this.extractNationalSignificantNumber(e.getNationalDigits(),(function(t){return e.update(t)}))}},{key:"isWaitingForCountryCallingCode",value:function(t){var e=t.international,d=t.callingCode;return e&&!d}},{key:"extractCountryCallingCode",value:function(t){var e=W("+"+t.getDigitsWithoutInternationalPrefix(),this.defaultCountry,this.defaultCallingCode,this.metadata.metadata),d=e.countryCallingCode,n=e.number;if(d)return t.setCallingCode(d),t.update({nationalSignificantNumber:n}),!0}},{key:"reset",value:function(t){if(t){this.hasSelectedNumberingPlan=!0;var e=t._nationalPrefixForParsing();this.couldPossiblyExtractAnotherNationalSignificantNumber=e&&Pn.test(e)}else this.hasSelectedNumberingPlan=void 0,this.couldPossiblyExtractAnotherNationalSignificantNumber=void 0}},{key:"extractNationalSignificantNumber",value:function(t,e){if(this.hasSelectedNumberingPlan){var d=B(t,this.metadata),n=d.nationalPrefix,r=d.nationalNumber,a=d.carrierCode;if(r!==t)return this.onExtractedNationalNumber(n,a,r,t,e),!0}}},{key:"extractAnotherNationalSignificantNumber",value:function(t,e,d){if(!this.hasExtractedNationalSignificantNumber)return this.extractNationalSignificantNumber(t,d);if(this.couldPossiblyExtractAnotherNationalSignificantNumber){var n=B(t,this.metadata),r=n.nationalPrefix,a=n.nationalNumber,i=n.carrierCode;if(a!==e)return this.onExtractedNationalNumber(r,i,a,t,d),!0}}},{key:"onExtractedNationalNumber",value:function(t,e,d,n,r){var a,i,o=n.lastIndexOf(d);if(o>=0&&o===n.length-d.length){i=!0;var $=n.slice(0,o);$!==t&&(a=$)}r({nationalPrefix:t,carrierCode:e,nationalSignificantNumber:d,nationalSignificantNumberMatchesInput:i,complexPrefixBeforeNationalSignificantNumber:a}),this.hasExtractedNationalSignificantNumber=!0,this.onNationalSignificantNumberChange()}},{key:"reExtractNationalSignificantNumber",value:function(t){return!!this.extractAnotherNationalSignificantNumber(t.getNationalDigits(),t.nationalSignificantNumber,(function(e){return t.update(e)}))||(this.extractIddPrefix(t)||this.fixMissingPlus(t)?(this.extractCallingCodeAndNationalSignificantNumber(t),!0):void 0)}},{key:"extractIddPrefix",value:function(t){var e=t.international,d=t.IDDPrefix,n=t.digits;if(t.nationalSignificantNumber,!e&&!d){var r=G(n,this.defaultCountry,this.defaultCallingCode,this.metadata.metadata);return void 0!==r&&r!==n?(t.update({IDDPrefix:n.slice(0,n.length-r.length)}),this.startInternationalNumber(t,{country:void 0,callingCode:void 0}),!0):void 0}}},{key:"fixMissingPlus",value:function(t){if(!t.international){var e=H(t.digits,this.defaultCountry,this.defaultCallingCode,this.metadata.metadata),d=e.countryCallingCode;if(e.number,d)return t.update({missingPlus:!0}),this.startInternationalNumber(t,{country:t.country,callingCode:d}),!0}}},{key:"startInternationalNumber",value:function(t,e){var d=e.country,n=e.callingCode;t.startInternationalNumber(d,n),t.nationalSignificantNumber&&(t.resetNationalSignificantNumber(),this.onNationalSignificantNumberChange(),this.hasExtractedNationalSignificantNumber=void 0)}},{key:"extractCallingCodeAndNationalSignificantNumber",value:function(t){this.extractCountryCallingCode(t)&&this.extractNationalSignificantNumber(t.getNationalDigits(),(function(e){return t.update(e)}))}}])&&bn(e.prototype,d),n&&bn(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function xn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var d=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null==d)return;var n,r,a=[],i=!0,o=!1;try{for(d=d.call(t);!(i=(n=d.next()).done)&&(a.push(n.value),!e||a.length!==e);i=!0);}catch(t){o=!0,r=t}finally{try{i||null==d.return||d.return()}finally{if(o)throw r}}return a}(t,e)||function(t,e){if(!t)return;if("string"==typeof t)return wn(t,e);var d=Object.prototype.toString.call(t).slice(8,-1);"Object"===d&&t.constructor&&(d=t.constructor.name);if("Map"===d||"Set"===d)return Array.from(t);if("Arguments"===d||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(d))return wn(t,e)}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function wn(t,e){(null==e||e>t.length)&&(e=t.length);for(var d=0,n=new Array(e);d<e;d++)n[d]=t[d];return n}function Sn(t,e){for(var d=0;d<e.length;d++){var n=e[d];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}var En=function(){function t(e,d){!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.metadata=new s(d);var n=xn(this.getCountryAndCallingCode(e),2),r=n[0],a=n[1];this.defaultCountry=r,this.defaultCallingCode=a,this.reset()}var e,d,n;return e=t,d=[{key:"getCountryAndCallingCode",value:function(t){var e,d;return t&&(a(t)?(e=t.defaultCountry,d=t.defaultCallingCode):e=t),e&&!this.metadata.hasCountry(e)&&(e=void 0),[e,d]}},{key:"input",value:function(t){var e=this.parser.input(t,this.state),d=e.digits;if(e.justLeadingPlus)this.formattedOutput="+";else if(d){var n;if(this.determineTheCountryIfNeeded(),this.state.nationalSignificantNumber&&this.formatter.narrowDownMatchingFormats(this.state),this.metadata.hasSelectedNumberingPlan()&&(n=this.formatter.format(d,this.state)),void 0===n&&this.parser.reExtractNationalSignificantNumber(this.state)){this.determineTheCountryIfNeeded();var r=this.state.getNationalDigits();r&&(n=this.formatter.format(r,this.state))}this.formattedOutput=n?this.getFullNumber(n):this.getNonFormattedNumber()}return this.formattedOutput}},{key:"reset",value:function(){var t=this;return this.state=new Hd({onCountryChange:function(e){t.country=e},onCallingCodeChange:function(e,d){t.metadata.selectNumberingPlan(d,e),t.formatter.reset(t.metadata.numberingPlan,t.state),t.parser.reset(t.metadata.numberingPlan)}}),this.formatter=new yn({state:this.state,metadata:this.metadata}),this.parser=new On({defaultCountry:this.defaultCountry,defaultCallingCode:this.defaultCallingCode,metadata:this.metadata,state:this.state,onNationalSignificantNumberChange:function(){t.determineTheCountryIfNeeded(),t.formatter.reset(t.metadata.numberingPlan,t.state)}}),this.state.reset({country:this.defaultCountry,callingCode:this.defaultCallingCode}),this.formattedOutput="",this}},{key:"isInternational",value:function(){return this.state.international}},{key:"getCallingCode",value:function(){if(this.isInternational())return this.state.callingCode}},{key:"getCountryCallingCode",value:function(){return this.getCallingCode()}},{key:"getCountry",value:function(){if(this.state.digits)return this._getCountry()}},{key:"_getCountry",value:function(){return this.state.country}},{key:"determineTheCountryIfNeeded",value:function(){this.state.country&&!this.isCountryCallingCodeAmbiguous()||this.determineTheCountry()}},{key:"getFullNumber",value:function(t){var e=this;if(this.isInternational()){var d=function(t){return e.formatter.getInternationalPrefixBeforeCountryCallingCode(e.state,{spacing:!!t})+t},n=this.state.callingCode;return d(n?t?"".concat(n," ").concat(t):n:"".concat(this.state.getDigitsWithoutInternationalPrefix()))}return t}},{key:"getNonFormattedNationalNumberWithPrefix",value:function(){var t=this.state,e=t.nationalSignificantNumber,d=t.complexPrefixBeforeNationalSignificantNumber,n=t.nationalPrefix,r=e,a=d||n;return a&&(r=a+r),r}},{key:"getNonFormattedNumber",value:function(){var t=this.state.nationalSignificantNumberMatchesInput;return this.getFullNumber(t?this.getNonFormattedNationalNumberWithPrefix():this.state.getNationalDigits())}},{key:"getNonFormattedTemplate",value:function(){var t=this.getNonFormattedNumber();if(t)return t.replace(/[\+\d]/g,Kd)}},{key:"isCountryCallingCodeAmbiguous",value:function(){var t=this.state.callingCode,e=this.metadata.getCountryCodesForCallingCode(t);return e&&e.length>1}},{key:"determineTheCountry",value:function(){this.state.setCountry(Vt(this.isInternational()?this.state.callingCode:this.defaultCallingCode,{nationalNumber:this.state.nationalSignificantNumber,defaultCountry:this.defaultCountry,metadata:this.metadata}))}},{key:"getNumberValue",value:function(){var t=this.state,e=t.digits,d=t.callingCode,n=t.country,r=t.nationalSignificantNumber;if(e)return this.isInternational()?d?"+"+d+r:"+"+e:n||d?"+"+(n?this.metadata.countryCallingCode():d)+r:void 0}},{key:"getNumber",value:function(){var t=this.state,e=t.nationalSignificantNumber,d=t.carrierCode,n=t.callingCode,r=this._getCountry();if(e&&(r||n)){if(r&&r===this.defaultCountry){var a=new s(this.metadata.metadata);a.selectNumberingPlan(r);var i=a.numberingPlan.callingCode(),o=this.metadata.getCountryCodesForCallingCode(i);if(o.length>1){var $=Wt(e,{countries:o,defaultCountry:this.defaultCountry,metadata:this.metadata.metadata});$&&(r=$)}}var u=new vt(r||n,e,this.metadata.metadata);return d&&(u.carrierCode=d),u}}},{key:"isPossible",value:function(){var t=this.getNumber();return!!t&&t.isPossible()}},{key:"isValid",value:function(){var t=this.getNumber();return!!t&&t.isValid()}},{key:"getNationalNumber",value:function(){return this.state.nationalSignificantNumber}},{key:"getChars",value:function(){return(this.state.international?"+":"")+this.state.digits}},{key:"getTemplate",value:function(){return this.formatter.getTemplate(this.state)||this.getNonFormattedTemplate()||""}}],d&&Sn(e.prototype,d),n&&Sn(e,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();function In(t){return new s(t).getCountries()}function An(t,e,d){if(e[t])return new vt(t,e[t],d)}function Tn(t,e,d){return d||(d=e,e=void 0),new En(e,d).input(t)}function jn(){return d(ue,arguments)}function kn(){return d(he,arguments)}function Fn(t,d){return Ad.call(this,t,d,e)}function Mn(t){return En.call(this,t,e)}function Dn(){return s.call(this,e)}function Rn(t){return vt.call(this,t,e)}Fn.prototype=Object.create(Ad.prototype,{}),Fn.prototype.constructor=Fn,Mn.prototype=Object.create(En.prototype,{}),Mn.prototype.constructor=Mn,Dn.prototype=Object.create(s.prototype,{}),Dn.prototype.constructor=Dn,Rn.prototype=Object.create(vt.prototype,{}),Rn.prototype.constructor=Rn,t.AsYouType=Mn,t.DIGIT_PLACEHOLDER=Kd,t.Metadata=Dn,t.ParseError=Tt,t.PhoneNumber=Rn,t.PhoneNumberMatcher=Fn,t.default=kn,t.findNumbers=function(){return d(Td,arguments)},t.findPhoneNumbersInText=function(){return d(Rd,arguments)},t.formatIncompletePhoneNumber=function(){return d(Tn,arguments)},t.formatRFC3966=at,t.getCountries=function(){return d(In,arguments)},t.getCountryCallingCode=function(){return d(C,arguments)},t.getExampleNumber=function(){return d(An,arguments)},t.getExtPrefix=function(){return d(v,arguments)},t.isPossiblePhoneNumber=function(){return d(Ne,arguments)},t.isSupportedCountry=function(){return d(N,arguments)},t.isValidPhoneNumber=function(){return d(pe,arguments)},t.parseDigits=Rt,t.parseIncompletePhoneNumber=Gt,t.parsePhoneNumber=jn,t.parsePhoneNumberCharacter=Bt,t.parsePhoneNumberFromString=kn,t.parsePhoneNumberWithError=jn,t.parseRFC3966=function(t){for(var e,d,n,r=function(t,e){var d="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(d)return(d=d.call(t)).next.bind(d);if(Array.isArray(t)||(d=nt(t))||e&&t&&"number"==typeof t.length){d&&(t=d);var n=0;return function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}((t=t.replace(/^tel:/,"tel=")).split(";"));!(n=r()).done;){var a=dt(n.value.split("="),2),i=a[0],o=a[1];switch(i){case"tel":e=o;break;case"ext":d=o;break;case"phone-context":"+"===o[0]&&(e=o+e)}}if(!et(e))return{};var $={number:e};return d&&($.ext=d),$},t.searchNumbers=function(){return d(kd,arguments)},t.searchPhoneNumbersInText=function(){return d(Bd,arguments)},t.validatePhoneNumberLength=function(){return d(we,arguments)},Object.defineProperty(t,"__esModule",{value:!0})}));


},{}],179:[function(require,module,exports){
/*!
* screenfull
* v3.3.3 - 2018-09-04
* (c) Sindre Sorhus; MIT License
*/
(function () {
	'use strict';

	var document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {};
	var isCommonjs = typeof module !== 'undefined' && module.exports;
	var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;

	var fn = (function () {
		var val;

		var fnMap = [
			[
				'requestFullscreen',
				'exitFullscreen',
				'fullscreenElement',
				'fullscreenEnabled',
				'fullscreenchange',
				'fullscreenerror'
			],
			// New WebKit
			[
				'webkitRequestFullscreen',
				'webkitExitFullscreen',
				'webkitFullscreenElement',
				'webkitFullscreenEnabled',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			// Old WebKit (Safari 5.1)
			[
				'webkitRequestFullScreen',
				'webkitCancelFullScreen',
				'webkitCurrentFullScreenElement',
				'webkitCancelFullScreen',
				'webkitfullscreenchange',
				'webkitfullscreenerror'

			],
			[
				'mozRequestFullScreen',
				'mozCancelFullScreen',
				'mozFullScreenElement',
				'mozFullScreenEnabled',
				'mozfullscreenchange',
				'mozfullscreenerror'
			],
			[
				'msRequestFullscreen',
				'msExitFullscreen',
				'msFullscreenElement',
				'msFullscreenEnabled',
				'MSFullscreenChange',
				'MSFullscreenError'
			]
		];

		var i = 0;
		var l = fnMap.length;
		var ret = {};

		for (; i < l; i++) {
			val = fnMap[i];
			if (val && val[1] in document) {
				for (i = 0; i < val.length; i++) {
					ret[fnMap[0][i]] = val[i];
				}
				return ret;
			}
		}

		return false;
	})();

	var eventNameMap = {
		change: fn.fullscreenchange,
		error: fn.fullscreenerror
	};

	var screenfull = {
		request: function (elem) {
			var request = fn.requestFullscreen;

			elem = elem || document.documentElement;

			// Work around Safari 5.1 bug: reports support for
			// keyboard in fullscreen even though it doesn't.
			// Browser sniffing, since the alternative with
			// setTimeout is even worse.
			if (/ Version\/5\.1(?:\.\d+)? Safari\//.test(navigator.userAgent)) {
				elem[request]();
			} else {
			    elem[request]({});
			}
		},
		exit: function () {
			document[fn.exitFullscreen]();
		},
		toggle: function (elem) {
			if (this.isFullscreen) {
				this.exit();
			} else {
				this.request(elem);
			}
		},
		onchange: function (callback) {
			this.on('change', callback);
		},
		onerror: function (callback) {
			this.on('error', callback);
		},
		on: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.addEventListener(eventName, callback, false);
			}
		},
		off: function (event, callback) {
			var eventName = eventNameMap[event];
			if (eventName) {
				document.removeEventListener(eventName, callback, false);
			}
		},
		raw: fn
	};

	if (!fn) {
		if (isCommonjs) {
			module.exports = false;
		} else {
			window.screenfull = false;
		}

		return;
	}

	Object.defineProperties(screenfull, {
		isFullscreen: {
			get: function () {
				return Boolean(document[fn.fullscreenElement]);
			}
		},
		element: {
			enumerable: true,
			get: function () {
				return document[fn.fullscreenElement];
			}
		},
		enabled: {
			enumerable: true,
			get: function () {
				// Coerce to boolean in case of old WebKit
				return Boolean(document[fn.fullscreenEnabled]);
			}
		}
	});

	if (isCommonjs) {
		module.exports = screenfull;
	} else {
		window.screenfull = screenfull;
	}
})();

},{}],180:[function(require,module,exports){
/*!
 * Select2 4.0.0
 * https://select2.github.io
 *
 * Released under the MIT license
 * https://github.com/select2/select2/blob/master/LICENSE.md
 */
(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function (jQuery) {
  // This is needed so we can catch the AMD loader configuration and use it
  // The inner file should be wrapped (by `banner.start.js`) in a function that
  // returns the AMD loader references.
  var S2 =
(function () {
  // Restore the Select2 AMD loader so it can be used
  // Needed mostly in the language files, where the loader is not inserted
  if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
    var S2 = jQuery.fn.select2.amd;
  }
var S2;(function () { if (!S2 || !S2.requirejs) {
if (!S2) { S2 = {}; } else { require = S2; }
/**
 * @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
 * Available via the MIT or new BSD license.
 * see: http://github.com/jrburke/almond for details
 */
//Going sloppy to avoid 'use strict' string cost, but strict practices should
//be followed.
/*jslint sloppy: true */
/*global setTimeout: false */

var requirejs, require, define;
(function (undef) {
    var main, req, makeMap, handlers,
        defined = {},
        waiting = {},
        config = {},
        defining = {},
        hasOwn = Object.prototype.hasOwnProperty,
        aps = [].slice,
        jsSuffixRegExp = /\.js$/;

    function hasProp(obj, prop) {
        return hasOwn.call(obj, prop);
    }

    /**
     * Given a relative module name, like ./something, normalize it to
     * a real name that can be mapped to a path.
     * @param {String} name the relative name
     * @param {String} baseName a real name that the name arg is relative
     * to.
     * @returns {String} normalized name
     */
    function normalize(name, baseName) {
        var nameParts, nameSegment, mapValue, foundMap, lastIndex,
            foundI, foundStarMap, starI, i, j, part,
            baseParts = baseName && baseName.split("/"),
            map = config.map,
            starMap = (map && map['*']) || {};

        //Adjust any relative paths.
        if (name && name.charAt(0) === ".") {
            //If have a base name, try to normalize against it,
            //otherwise, assume it is a top-level require that will
            //be relative to baseUrl in the end.
            if (baseName) {
                //Convert baseName to array, and lop off the last part,
                //so that . matches that "directory" and not name of the baseName's
                //module. For instance, baseName of "one/two/three", maps to
                //"one/two/three.js", but we want the directory, "one/two" for
                //this normalization.
                baseParts = baseParts.slice(0, baseParts.length - 1);
                name = name.split('/');
                lastIndex = name.length - 1;

                // Node .js allowance:
                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
                }

                name = baseParts.concat(name);

                //start trimDots
                for (i = 0; i < name.length; i += 1) {
                    part = name[i];
                    if (part === ".") {
                        name.splice(i, 1);
                        i -= 1;
                    } else if (part === "..") {
                        if (i === 1 && (name[2] === '..' || name[0] === '..')) {
                            //End of the line. Keep at least one non-dot
                            //path segment at the front so it can be mapped
                            //correctly to disk. Otherwise, there is likely
                            //no path mapping for a path starting with '..'.
                            //This can still fail, but catches the most reasonable
                            //uses of ..
                            break;
                        } else if (i > 0) {
                            name.splice(i - 1, 2);
                            i -= 2;
                        }
                    }
                }
                //end trimDots

                name = name.join("/");
            } else if (name.indexOf('./') === 0) {
                // No baseName, so this is ID is resolved relative
                // to baseUrl, pull off the leading dot.
                name = name.substring(2);
            }
        }

        //Apply map config if available.
        if ((baseParts || starMap) && map) {
            nameParts = name.split('/');

            for (i = nameParts.length; i > 0; i -= 1) {
                nameSegment = nameParts.slice(0, i).join("/");

                if (baseParts) {
                    //Find the longest baseName segment match in the config.
                    //So, do joins on the biggest to smallest lengths of baseParts.
                    for (j = baseParts.length; j > 0; j -= 1) {
                        mapValue = map[baseParts.slice(0, j).join('/')];

                        //baseName segment has  config, find if it has one for
                        //this name.
                        if (mapValue) {
                            mapValue = mapValue[nameSegment];
                            if (mapValue) {
                                //Match, update name to the new value.
                                foundMap = mapValue;
                                foundI = i;
                                break;
                            }
                        }
                    }
                }

                if (foundMap) {
                    break;
                }

                //Check for a star map match, but just hold on to it,
                //if there is a shorter segment match later in a matching
                //config, then favor over this star map.
                if (!foundStarMap && starMap && starMap[nameSegment]) {
                    foundStarMap = starMap[nameSegment];
                    starI = i;
                }
            }

            if (!foundMap && foundStarMap) {
                foundMap = foundStarMap;
                foundI = starI;
            }

            if (foundMap) {
                nameParts.splice(0, foundI, foundMap);
                name = nameParts.join('/');
            }
        }

        return name;
    }

    function makeRequire(relName, forceSync) {
        return function () {
            //A version of a require function that passes a moduleName
            //value for items that may need to
            //look up paths relative to the moduleName
            return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync]));
        };
    }

    function makeNormalize(relName) {
        return function (name) {
            return normalize(name, relName);
        };
    }

    function makeLoad(depName) {
        return function (value) {
            defined[depName] = value;
        };
    }

    function callDep(name) {
        if (hasProp(waiting, name)) {
            var args = waiting[name];
            delete waiting[name];
            defining[name] = true;
            main.apply(undef, args);
        }

        if (!hasProp(defined, name) && !hasProp(defining, name)) {
            throw new Error('No ' + name);
        }
        return defined[name];
    }

    //Turns a plugin!resource to [plugin, resource]
    //with the plugin being undefined if the name
    //did not have a plugin prefix.
    function splitPrefix(name) {
        var prefix,
            index = name ? name.indexOf('!') : -1;
        if (index > -1) {
            prefix = name.substring(0, index);
            name = name.substring(index + 1, name.length);
        }
        return [prefix, name];
    }

    /**
     * Makes a name map, normalizing the name, and using a plugin
     * for normalization if necessary. Grabs a ref to plugin
     * too, as an optimization.
     */
    makeMap = function (name, relName) {
        var plugin,
            parts = splitPrefix(name),
            prefix = parts[0];

        name = parts[1];

        if (prefix) {
            prefix = normalize(prefix, relName);
            plugin = callDep(prefix);
        }

        //Normalize according
        if (prefix) {
            if (plugin && plugin.normalize) {
                name = plugin.normalize(name, makeNormalize(relName));
            } else {
                name = normalize(name, relName);
            }
        } else {
            name = normalize(name, relName);
            parts = splitPrefix(name);
            prefix = parts[0];
            name = parts[1];
            if (prefix) {
                plugin = callDep(prefix);
            }
        }

        //Using ridiculous property names for space reasons
        return {
            f: prefix ? prefix + '!' + name : name, //fullName
            n: name,
            pr: prefix,
            p: plugin
        };
    };

    function makeConfig(name) {
        return function () {
            return (config && config.config && config.config[name]) || {};
        };
    }

    handlers = {
        require: function (name) {
            return makeRequire(name);
        },
        exports: function (name) {
            var e = defined[name];
            if (typeof e !== 'undefined') {
                return e;
            } else {
                return (defined[name] = {});
            }
        },
        module: function (name) {
            return {
                id: name,
                uri: '',
                exports: defined[name],
                config: makeConfig(name)
            };
        }
    };

    main = function (name, deps, callback, relName) {
        var cjsModule, depName, ret, map, i,
            args = [],
            callbackType = typeof callback,
            usingExports;

        //Use name if no relName
        relName = relName || name;

        //Call the callback to define the module, if necessary.
        if (callbackType === 'undefined' || callbackType === 'function') {
            //Pull out the defined dependencies and pass the ordered
            //values to the callback.
            //Default to [require, exports, module] if no deps
            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
            for (i = 0; i < deps.length; i += 1) {
                map = makeMap(deps[i], relName);
                depName = map.f;

                //Fast path CommonJS standard dependencies.
                if (depName === "require") {
                    args[i] = handlers.require(name);
                } else if (depName === "exports") {
                    //CommonJS module spec 1.1
                    args[i] = handlers.exports(name);
                    usingExports = true;
                } else if (depName === "module") {
                    //CommonJS module spec 1.1
                    cjsModule = args[i] = handlers.module(name);
                } else if (hasProp(defined, depName) ||
                           hasProp(waiting, depName) ||
                           hasProp(defining, depName)) {
                    args[i] = callDep(depName);
                } else if (map.p) {
                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
                    args[i] = defined[depName];
                } else {
                    throw new Error(name + ' missing ' + depName);
                }
            }

            ret = callback ? callback.apply(defined[name], args) : undefined;

            if (name) {
                //If setting exports via "module" is in play,
                //favor that over return value and exports. After that,
                //favor a non-undefined return value over exports use.
                if (cjsModule && cjsModule.exports !== undef &&
                        cjsModule.exports !== defined[name]) {
                    defined[name] = cjsModule.exports;
                } else if (ret !== undef || !usingExports) {
                    //Use the return value from the function.
                    defined[name] = ret;
                }
            }
        } else if (name) {
            //May just be an object definition for the module. Only
            //worry about defining if have a module name.
            defined[name] = callback;
        }
    };

    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
        if (typeof deps === "string") {
            if (handlers[deps]) {
                //callback in this case is really relName
                return handlers[deps](callback);
            }
            //Just return the module wanted. In this scenario, the
            //deps arg is the module name, and second arg (if passed)
            //is just the relName.
            //Normalize module name, if it contains . or ..
            return callDep(makeMap(deps, callback).f);
        } else if (!deps.splice) {
            //deps is a config object, not an array.
            config = deps;
            if (config.deps) {
                req(config.deps, config.callback);
            }
            if (!callback) {
                return;
            }

            if (callback.splice) {
                //callback is an array, which means it is a dependency list.
                //Adjust args if there are dependencies
                deps = callback;
                callback = relName;
                relName = null;
            } else {
                deps = undef;
            }
        }

        //Support require(['a'])
        callback = callback || function () {};

        //If relName is a function, it is an errback handler,
        //so remove it.
        if (typeof relName === 'function') {
            relName = forceSync;
            forceSync = alt;
        }

        //Simulate async callback;
        if (forceSync) {
            main(undef, deps, callback, relName);
        } else {
            //Using a non-zero value because of concern for what old browsers
            //do, and latest browsers "upgrade" to 4 if lower value is used:
            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
            //If want a value immediately, use require('id') instead -- something
            //that works in almond on the global level, but not guaranteed and
            //unlikely to work in other AMD implementations.
            setTimeout(function () {
                main(undef, deps, callback, relName);
            }, 4);
        }

        return req;
    };

    /**
     * Just drops the config on the floor, but returns req in case
     * the config return value is used.
     */
    req.config = function (cfg) {
        return req(cfg);
    };

    /**
     * Expose module registry for debugging and tooling
     */
    requirejs._defined = defined;

    define = function (name, deps, callback) {

        //This module may not have dependencies
        if (!deps.splice) {
            //deps is not an array, so probably means
            //an object literal or factory function for
            //the value. Adjust args.
            callback = deps;
            deps = [];
        }

        if (!hasProp(defined, name) && !hasProp(waiting, name)) {
            waiting[name] = [name, deps, callback];
        }
    };

    define.amd = {
        jQuery: true
    };
}());

S2.requirejs = requirejs;S2.require = require;S2.define = define;
}
}());
S2.define("almond", function(){});

/* global jQuery:false, $:false */
S2.define('jquery',[],function () {
  var _$ = jQuery || $;

  if (_$ == null && console && console.error) {
    console.error(
      'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
      'found. Make sure that you are including jQuery before Select2 on your ' +
      'web page.'
    );
  }

  return _$;
});

S2.define('select2/utils',[
  'jquery'
], function ($) {
  var Utils = {};

  Utils.Extend = function (ChildClass, SuperClass) {
    var __hasProp = {}.hasOwnProperty;

    function BaseConstructor () {
      this.constructor = ChildClass;
    }

    for (var key in SuperClass) {
      if (__hasProp.call(SuperClass, key)) {
        ChildClass[key] = SuperClass[key];
      }
    }

    BaseConstructor.prototype = SuperClass.prototype;
    ChildClass.prototype = new BaseConstructor();
    ChildClass.__super__ = SuperClass.prototype;

    return ChildClass;
  };

  function getMethods (theClass) {
    var proto = theClass.prototype;

    var methods = [];

    for (var methodName in proto) {
      var m = proto[methodName];

      if (typeof m !== 'function') {
        continue;
      }

      if (methodName === 'constructor') {
        continue;
      }

      methods.push(methodName);
    }

    return methods;
  }

  Utils.Decorate = function (SuperClass, DecoratorClass) {
    var decoratedMethods = getMethods(DecoratorClass);
    var superMethods = getMethods(SuperClass);

    function DecoratedClass () {
      var unshift = Array.prototype.unshift;

      var argCount = DecoratorClass.prototype.constructor.length;

      var calledConstructor = SuperClass.prototype.constructor;

      if (argCount > 0) {
        unshift.call(arguments, SuperClass.prototype.constructor);

        calledConstructor = DecoratorClass.prototype.constructor;
      }

      calledConstructor.apply(this, arguments);
    }

    DecoratorClass.displayName = SuperClass.displayName;

    function ctr () {
      this.constructor = DecoratedClass;
    }

    DecoratedClass.prototype = new ctr();

    for (var m = 0; m < superMethods.length; m++) {
        var superMethod = superMethods[m];

        DecoratedClass.prototype[superMethod] =
          SuperClass.prototype[superMethod];
    }

    var calledMethod = function (methodName) {
      // Stub out the original method if it's not decorating an actual method
      var originalMethod = function () {};

      if (methodName in DecoratedClass.prototype) {
        originalMethod = DecoratedClass.prototype[methodName];
      }

      var decoratedMethod = DecoratorClass.prototype[methodName];

      return function () {
        var unshift = Array.prototype.unshift;

        unshift.call(arguments, originalMethod);

        return decoratedMethod.apply(this, arguments);
      };
    };

    for (var d = 0; d < decoratedMethods.length; d++) {
      var decoratedMethod = decoratedMethods[d];

      DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
    }

    return DecoratedClass;
  };

  var Observable = function () {
    this.listeners = {};
  };

  Observable.prototype.on = function (event, callback) {
    this.listeners = this.listeners || {};

    if (event in this.listeners) {
      this.listeners[event].push(callback);
    } else {
      this.listeners[event] = [callback];
    }
  };

  Observable.prototype.trigger = function (event) {
    var slice = Array.prototype.slice;

    this.listeners = this.listeners || {};

    if (event in this.listeners) {
      this.invoke(this.listeners[event], slice.call(arguments, 1));
    }

    if ('*' in this.listeners) {
      this.invoke(this.listeners['*'], arguments);
    }
  };

  Observable.prototype.invoke = function (listeners, params) {
    for (var i = 0, len = listeners.length; i < len; i++) {
      listeners[i].apply(this, params);
    }
  };

  Utils.Observable = Observable;

  Utils.generateChars = function (length) {
    var chars = '';

    for (var i = 0; i < length; i++) {
      var randomChar = Math.floor(Math.random() * 36);
      chars += randomChar.toString(36);
    }

    return chars;
  };

  Utils.bind = function (func, context) {
    return function () {
      func.apply(context, arguments);
    };
  };

  Utils._convertData = function (data) {
    for (var originalKey in data) {
      var keys = originalKey.split('-');

      var dataLevel = data;

      if (keys.length === 1) {
        continue;
      }

      for (var k = 0; k < keys.length; k++) {
        var key = keys[k];

        // Lowercase the first letter
        // By default, dash-separated becomes camelCase
        key = key.substring(0, 1).toLowerCase() + key.substring(1);

        if (!(key in dataLevel)) {
          dataLevel[key] = {};
        }

        if (k == keys.length - 1) {
          dataLevel[key] = data[originalKey];
        }

        dataLevel = dataLevel[key];
      }

      delete data[originalKey];
    }

    return data;
  };

  Utils.hasScroll = function (index, el) {
    // Adapted from the function created by @ShadowScripter
    // and adapted by @BillBarry on the Stack Exchange Code Review website.
    // The original code can be found at
    // http://codereview.stackexchange.com/q/13338
    // and was designed to be used with the Sizzle selector engine.

    var $el = $(el);
    var overflowX = el.style.overflowX;
    var overflowY = el.style.overflowY;

    //Check both x and y declarations
    if (overflowX === overflowY &&
        (overflowY === 'hidden' || overflowY === 'visible')) {
      return false;
    }

    if (overflowX === 'scroll' || overflowY === 'scroll') {
      return true;
    }

    return ($el.innerHeight() < el.scrollHeight ||
      $el.innerWidth() < el.scrollWidth);
  };

  Utils.escapeMarkup = function (markup) {
    var replaceMap = {
      '\\': '&#92;',
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      '\'': '&#39;',
      '/': '&#47;'
    };

    // Do not try to escape the markup if it's not a string
    if (typeof markup !== 'string') {
      return markup;
    }

    return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
      return replaceMap[match];
    });
  };

  // Append an array of jQuery nodes to a given element.
  Utils.appendMany = function ($element, $nodes) {
    // jQuery 1.7.x does not support $.fn.append() with an array
    // Fall back to a jQuery object collection using $.fn.add()
    if ($.fn.jquery.substr(0, 3) === '1.7') {
      var $jqNodes = $();

      $.map($nodes, function (node) {
        $jqNodes = $jqNodes.add(node);
      });

      $nodes = $jqNodes;
    }

    $element.append($nodes);
  };

  return Utils;
});

S2.define('select2/results',[
  'jquery',
  './utils'
], function ($, Utils) {
  function Results ($element, options, dataAdapter) {
    this.$element = $element;
    this.data = dataAdapter;
    this.options = options;

    Results.__super__.constructor.call(this);
  }

  Utils.Extend(Results, Utils.Observable);

  Results.prototype.render = function () {
    var $results = $(
      '<ul class="select2-results__options" role="tree"></ul>'
    );

    if (this.options.get('multiple')) {
      $results.attr('aria-multiselectable', 'true');
    }

    this.$results = $results;

    return $results;
  };

  Results.prototype.clear = function () {
    this.$results.empty();
  };

  Results.prototype.displayMessage = function (params) {
    var escapeMarkup = this.options.get('escapeMarkup');

    this.clear();
    this.hideLoading();

    var $message = $(
      '<li role="treeitem" class="select2-results__option"></li>'
    );

    var message = this.options.get('translations').get(params.message);

    $message.append(
      escapeMarkup(
        message(params.args)
      )
    );

    this.$results.append($message);
  };

  Results.prototype.append = function (data) {
    this.hideLoading();

    var $options = [];

    if (data.results == null || data.results.length === 0) {
      if (this.$results.children().length === 0) {
        this.trigger('results:message', {
          message: 'noResults'
        });
      }

      return;
    }

    data.results = this.sort(data.results);

    for (var d = 0; d < data.results.length; d++) {
      var item = data.results[d];

      var $option = this.option(item);

      $options.push($option);
    }

    this.$results.append($options);
  };

  Results.prototype.position = function ($results, $dropdown) {
    var $resultsContainer = $dropdown.find('.select2-results');
    $resultsContainer.append($results);
  };

  Results.prototype.sort = function (data) {
    var sorter = this.options.get('sorter');

    return sorter(data);
  };

  Results.prototype.setClasses = function () {
    var self = this;

    this.data.current(function (selected) {
      var selectedIds = $.map(selected, function (s) {
        return s.id.toString();
      });

      var $options = self.$results
        .find('.select2-results__option[aria-selected]');

      $options.each(function () {
        var $option = $(this);

        var item = $.data(this, 'data');

        // id needs to be converted to a string when comparing
        var id = '' + item.id;

        if ((item.element != null && item.element.selected) ||
            (item.element == null && $.inArray(id, selectedIds) > -1)) {
          $option.attr('aria-selected', 'true');
        } else {
          $option.attr('aria-selected', 'false');
        }
      });

      var $selected = $options.filter('[aria-selected=true]');

      // Check if there are any selected options
      if ($selected.length > 0) {
        // If there are selected options, highlight the first
        $selected.first().trigger('mouseenter');
      } else {
        // If there are no selected options, highlight the first option
        // in the dropdown
        $options.first().trigger('mouseenter');
      }
    });
  };

  Results.prototype.showLoading = function (params) {
    this.hideLoading();

    var loadingMore = this.options.get('translations').get('searching');

    var loading = {
      disabled: true,
      loading: true,
      text: loadingMore(params)
    };
    var $loading = this.option(loading);
    $loading.className += ' loading-results';

    this.$results.prepend($loading);
  };

  Results.prototype.hideLoading = function () {
    this.$results.find('.loading-results').remove();
  };

  Results.prototype.option = function (data) {
    var option = document.createElement('li');
    option.className = 'select2-results__option';

    var attrs = {
      'role': 'treeitem',
      'aria-selected': 'false'
    };

    if (data.disabled) {
      delete attrs['aria-selected'];
      attrs['aria-disabled'] = 'true';
    }

    if (data.id == null) {
      delete attrs['aria-selected'];
    }

    if (data._resultId != null) {
      option.id = data._resultId;
    }

    if (data.title) {
      option.title = data.title;
    }

    if (data.children) {
      attrs.role = 'group';
      attrs['aria-label'] = data.text;
      delete attrs['aria-selected'];
    }

    for (var attr in attrs) {
      var val = attrs[attr];

      option.setAttribute(attr, val);
    }

    if (data.children) {
      var $option = $(option);

      var label = document.createElement('strong');
      label.className = 'select2-results__group';

      var $label = $(label);
      this.template(data, label);

      var $children = [];

      for (var c = 0; c < data.children.length; c++) {
        var child = data.children[c];

        var $child = this.option(child);

        $children.push($child);
      }

      var $childrenContainer = $('<ul></ul>', {
        'class': 'select2-results__options select2-results__options--nested'
      });

      $childrenContainer.append($children);

      $option.append(label);
      $option.append($childrenContainer);
    } else {
      this.template(data, option);
    }

    $.data(option, 'data', data);

    return option;
  };

  Results.prototype.bind = function (container, $container) {
    var self = this;

    var id = container.id + '-results';

    this.$results.attr('id', id);

    container.on('results:all', function (params) {
      self.clear();
      self.append(params.data);

      if (container.isOpen()) {
        self.setClasses();
      }
    });

    container.on('results:append', function (params) {
      self.append(params.data);

      if (container.isOpen()) {
        self.setClasses();
      }
    });

    container.on('query', function (params) {
      self.showLoading(params);
    });

    container.on('select', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();
    });

    container.on('unselect', function () {
      if (!container.isOpen()) {
        return;
      }

      self.setClasses();
    });

    container.on('open', function () {
      // When the dropdown is open, aria-expended="true"
      self.$results.attr('aria-expanded', 'true');
      self.$results.attr('aria-hidden', 'false');

      self.setClasses();
      self.ensureHighlightVisible();
    });

    container.on('close', function () {
      // When the dropdown is closed, aria-expended="false"
      self.$results.attr('aria-expanded', 'false');
      self.$results.attr('aria-hidden', 'true');
      self.$results.removeAttr('aria-activedescendant');
    });

    container.on('results:toggle', function () {
      var $highlighted = self.getHighlightedResults();

      if ($highlighted.length === 0) {
        return;
      }

      $highlighted.trigger('mouseup');
    });

    container.on('results:select', function () {
      var $highlighted = self.getHighlightedResults();

      if ($highlighted.length === 0) {
        return;
      }

      var data = $highlighted.data('data');

      if ($highlighted.attr('aria-selected') == 'true') {
        self.trigger('close', {});
      } else {
        self.trigger('select', {
          data: data
        });
      }
    });

    container.on('results:previous', function () {
      var $highlighted = self.getHighlightedResults();

      var $options = self.$results.find('[aria-selected]');

      var currentIndex = $options.index($highlighted);

      // If we are already at te top, don't move further
      if (currentIndex === 0) {
        return;
      }

      var nextIndex = currentIndex - 1;

      // If none are highlighted, highlight the first
      if ($highlighted.length === 0) {
        nextIndex = 0;
      }

      var $next = $options.eq(nextIndex);

      $next.trigger('mouseenter');

      var currentOffset = self.$results.offset().top;
      var nextTop = $next.offset().top;
      var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);

      if (nextIndex === 0) {
        self.$results.scrollTop(0);
      } else if (nextTop - currentOffset < 0) {
        self.$results.scrollTop(nextOffset);
      }
    });

    container.on('results:next', function () {
      var $highlighted = self.getHighlightedResults();

      var $options = self.$results.find('[aria-selected]');

      var currentIndex = $options.index($highlighted);

      var nextIndex = currentIndex + 1;

      // If we are at the last option, stay there
      if (nextIndex >= $options.length) {
        return;
      }

      var $next = $options.eq(nextIndex);

      $next.trigger('mouseenter');

      var currentOffset = self.$results.offset().top +
        self.$results.outerHeight(false);
      var nextBottom = $next.offset().top + $next.outerHeight(false);
      var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;

      if (nextIndex === 0) {
        self.$results.scrollTop(0);
      } else if (nextBottom > currentOffset) {
        self.$results.scrollTop(nextOffset);
      }
    });

    container.on('results:focus', function (params) {
      params.element.addClass('select2-results__option--highlighted');
    });

    container.on('results:message', function (params) {
      self.displayMessage(params);
    });

    if ($.fn.mousewheel) {
      this.$results.on('mousewheel', function (e) {
        var top = self.$results.scrollTop();

        var bottom = (
          self.$results.get(0).scrollHeight -
          self.$results.scrollTop() +
          e.deltaY
        );

        var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
        var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();

        if (isAtTop) {
          self.$results.scrollTop(0);

          e.preventDefault();
          e.stopPropagation();
        } else if (isAtBottom) {
          self.$results.scrollTop(
            self.$results.get(0).scrollHeight - self.$results.height()
          );

          e.preventDefault();
          e.stopPropagation();
        }
      });
    }

    this.$results.on('mouseup', '.select2-results__option[aria-selected]',
      function (evt) {
      var $this = $(this);

      var data = $this.data('data');

      if ($this.attr('aria-selected') === 'true') {
        if (self.options.get('multiple')) {
          self.trigger('unselect', {
            originalEvent: evt,
            data: data
          });
        } else {
          self.trigger('close', {});
        }

        return;
      }

      self.trigger('select', {
        originalEvent: evt,
        data: data
      });
    });

    this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
      function (evt) {
      var data = $(this).data('data');

      self.getHighlightedResults()
          .removeClass('select2-results__option--highlighted');

      self.trigger('results:focus', {
        data: data,
        element: $(this)
      });
    });
  };

  Results.prototype.getHighlightedResults = function () {
    var $highlighted = this.$results
    .find('.select2-results__option--highlighted');

    return $highlighted;
  };

  Results.prototype.destroy = function () {
    this.$results.remove();
  };

  Results.prototype.ensureHighlightVisible = function () {
    var $highlighted = this.getHighlightedResults();

    if ($highlighted.length === 0) {
      return;
    }

    var $options = this.$results.find('[aria-selected]');

    var currentIndex = $options.index($highlighted);

    var currentOffset = this.$results.offset().top;
    var nextTop = $highlighted.offset().top;
    var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);

    var offsetDelta = nextTop - currentOffset;
    nextOffset -= $highlighted.outerHeight(false) * 2;

    if (currentIndex <= 2) {
      this.$results.scrollTop(0);
    } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
      this.$results.scrollTop(nextOffset);
    }
  };

  Results.prototype.template = function (result, container) {
    var template = this.options.get('templateResult');
    var escapeMarkup = this.options.get('escapeMarkup');

    var content = template(result);

    if (content == null) {
      container.style.display = 'none';
    } else if (typeof content === 'string') {
      container.innerHTML = escapeMarkup(content);
    } else {
      $(container).append(content);
    }
  };

  return Results;
});

S2.define('select2/keys',[

], function () {
  var KEYS = {
    BACKSPACE: 8,
    TAB: 9,
    ENTER: 13,
    SHIFT: 16,
    CTRL: 17,
    ALT: 18,
    ESC: 27,
    SPACE: 32,
    PAGE_UP: 33,
    PAGE_DOWN: 34,
    END: 35,
    HOME: 36,
    LEFT: 37,
    UP: 38,
    RIGHT: 39,
    DOWN: 40,
    DELETE: 46
  };

  return KEYS;
});

S2.define('select2/selection/base',[
  'jquery',
  '../utils',
  '../keys'
], function ($, Utils, KEYS) {
  function BaseSelection ($element, options) {
    this.$element = $element;
    this.options = options;

    BaseSelection.__super__.constructor.call(this);
  }

  Utils.Extend(BaseSelection, Utils.Observable);

  BaseSelection.prototype.render = function () {
    var $selection = $(
      '<span class="select2-selection" role="combobox" ' +
      'aria-autocomplete="list" aria-haspopup="true" aria-expanded="false">' +
      '</span>'
    );

    this._tabindex = 0;

    if (this.$element.data('old-tabindex') != null) {
      this._tabindex = this.$element.data('old-tabindex');
    } else if (this.$element.attr('tabindex') != null) {
      this._tabindex = this.$element.attr('tabindex');
    }

    $selection.attr('title', this.$element.attr('title'));
    $selection.attr('tabindex', this._tabindex);

    this.$selection = $selection;

    return $selection;
  };

  BaseSelection.prototype.bind = function (container, $container) {
    var self = this;

    var id = container.id + '-container';
    var resultsId = container.id + '-results';

    this.container = container;

    this.$selection.on('focus', function (evt) {
      self.trigger('focus', evt);
    });

    this.$selection.on('blur', function (evt) {
      self._handleBlur(evt);
    });

    this.$selection.on('keydown', function (evt) {
      self.trigger('keypress', evt);

      if (evt.which === KEYS.SPACE) {
        evt.preventDefault();
      }
    });

    container.on('results:focus', function (params) {
      self.$selection.attr('aria-activedescendant', params.data._resultId);
    });

    container.on('selection:update', function (params) {
      self.update(params.data);
    });

    container.on('open', function () {
      // When the dropdown is open, aria-expanded="true"
      self.$selection.attr('aria-expanded', 'true');
      self.$selection.attr('aria-owns', resultsId);

      self._attachCloseHandler(container);
    });

    container.on('close', function () {
      // When the dropdown is closed, aria-expanded="false"
      self.$selection.attr('aria-expanded', 'false');
      self.$selection.removeAttr('aria-activedescendant');
      self.$selection.removeAttr('aria-owns');

      self.$selection.focus();

      self._detachCloseHandler(container);
    });

    container.on('enable', function () {
      self.$selection.attr('tabindex', self._tabindex);
    });

    container.on('disable', function () {
      self.$selection.attr('tabindex', '-1');
    });
  };

  BaseSelection.prototype._handleBlur = function (evt) {
    var self = this;

    // This needs to be delayed as the actve element is the body when the tab
    // key is pressed, possibly along with others.
    window.setTimeout(function () {
      // Don't trigger `blur` if the focus is still in the selection
      if (
        (document.activeElement == self.$selection[0]) ||
        ($.contains(self.$selection[0], document.activeElement))
      ) {
        return;
      }

      self.trigger('blur', evt);
    }, 1);
  };

  BaseSelection.prototype._attachCloseHandler = function (container) {
    var self = this;

    $(document.body).on('mousedown.select2.' + container.id, function (e) {
      var $target = $(e.target);

      var $select = $target.closest('.select2');

      var $all = $('.select2.select2-container--open');

      $all.each(function () {
        var $this = $(this);

        if (this == $select[0]) {
          return;
        }

        var $element = $this.data('element');

        $element.select2('close');
      });
    });
  };

  BaseSelection.prototype._detachCloseHandler = function (container) {
    $(document.body).off('mousedown.select2.' + container.id);
  };

  BaseSelection.prototype.position = function ($selection, $container) {
    var $selectionContainer = $container.find('.selection');
    $selectionContainer.append($selection);
  };

  BaseSelection.prototype.destroy = function () {
    this._detachCloseHandler(this.container);
  };

  BaseSelection.prototype.update = function (data) {
    throw new Error('The `update` method must be defined in child classes.');
  };

  return BaseSelection;
});

S2.define('select2/selection/single',[
  'jquery',
  './base',
  '../utils',
  '../keys'
], function ($, BaseSelection, Utils, KEYS) {
  function SingleSelection () {
    SingleSelection.__super__.constructor.apply(this, arguments);
  }

  Utils.Extend(SingleSelection, BaseSelection);

  SingleSelection.prototype.render = function () {
    var $selection = SingleSelection.__super__.render.call(this);

    $selection.addClass('select2-selection--single');

    $selection.html(
      '<span class="select2-selection__rendered"></span>' +
      '<span class="select2-selection__arrow" role="presentation">' +
        '<b role="presentation"></b>' +
      '</span>'
    );

    return $selection;
  };

  SingleSelection.prototype.bind = function (container, $container) {
    var self = this;

    SingleSelection.__super__.bind.apply(this, arguments);

    var id = container.id + '-container';

    this.$selection.find('.select2-selection__rendered').attr('id', id);
    this.$selection.attr('aria-labelledby', id);

    this.$selection.on('mousedown', function (evt) {
      // Only respond to left clicks
      if (evt.which !== 1) {
        return;
      }

      self.trigger('toggle', {
        originalEvent: evt
      });
    });

    this.$selection.on('focus', function (evt) {
      // User focuses on the container
    });

    this.$selection.on('blur', function (evt) {
      // User exits the container
    });

    container.on('selection:update', function (params) {
      self.update(params.data);
    });
  };

  SingleSelection.prototype.clear = function () {
    this.$selection.find('.select2-selection__rendered').empty();
  };

  SingleSelection.prototype.display = function (data, container) {
    var template = this.options.get('templateSelection');
    var escapeMarkup = this.options.get('escapeMarkup');

    return escapeMarkup(template(data, container));
  };

  SingleSelection.prototype.selectionContainer = function () {
    return $('<span></span>');
  };

  SingleSelection.prototype.update = function (data) {
    if (data.length === 0) {
      this.clear();
      return;
    }

    var selection = data[0];

    var $rendered = this.$selection.find('.select2-selection__rendered');
    var formatted = this.display(selection, $rendered);

    $rendered.empty().append(formatted);
    $rendered.prop('title', selection.title || selection.text);
  };

  return SingleSelection;
});

S2.define('select2/selection/multiple',[
  'jquery',
  './base',
  '../utils'
], function ($, BaseSelection, Utils) {
  function MultipleSelection ($element, options) {
    MultipleSelection.__super__.constructor.apply(this, arguments);
  }

  Utils.Extend(MultipleSelection, BaseSelection);

  MultipleSelection.prototype.render = function () {
    var $selection = MultipleSelection.__super__.render.call(this);

    $selection.addClass('select2-selection--multiple');

    $selection.html(
      '<ul class="select2-selection__rendered"></ul>'
    );

    return $selection;
  };

  MultipleSelection.prototype.bind = function (container, $container) {
    var self = this;

    MultipleSelection.__super__.bind.apply(this, arguments);

    this.$selection.on('click', function (evt) {
      self.trigger('toggle', {
        originalEvent: evt
      });
    });

    this.$selection.on(
      'click',
      '.select2-selection__choice__remove',
      function (evt) {
        // Ignore the event if it is disabled
        if (self.options.get('disabled')) {
          return;
        }

        var $remove = $(this);
        var $selection = $remove.parent();

        var data = $selection.data('data');

        self.trigger('unselect', {
          originalEvent: evt,
          data: data
        });
      }
    );
  };

  MultipleSelection.prototype.clear = function () {
    this.$selection.find('.select2-selection__rendered').empty();
  };

  MultipleSelection.prototype.display = function (data, container) {
    var template = this.options.get('templateSelection');
    var escapeMarkup = this.options.get('escapeMarkup');

    return escapeMarkup(template(data, container));
  };

  MultipleSelection.prototype.selectionContainer = function () {
    var $container = $(
      '<li class="select2-selection__choice">' +
        '<span class="select2-selection__choice__remove" role="presentation">' +
          '<i class="icon-cross"></i>' +
        '</span>' +
      '</li>'
    );

    return $container;
  };

  MultipleSelection.prototype.update = function (data) {
    this.clear();

    if (data.length === 0) {
      return;
    }

    var $selections = [];

    for (var d = 0; d < data.length; d++) {
      var selection = data[d];

      var $selection = this.selectionContainer();
      var formatted = this.display(selection, $selection);

      $selection.append(formatted);
      $selection.prop('title', selection.title || selection.text);

      $selection.data('data', selection);

      $selections.push($selection);
    }

    var $rendered = this.$selection.find('.select2-selection__rendered');

    Utils.appendMany($rendered, $selections);
  };

  return MultipleSelection;
});

S2.define('select2/selection/placeholder',[
  '../utils'
], function (Utils) {
  function Placeholder (decorated, $element, options) {
    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));

    decorated.call(this, $element, options);
  }

  Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
    if (typeof placeholder === 'string') {
      placeholder = {
        id: '',
        text: placeholder
      };
    }

    return placeholder;
  };

  Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
    var $placeholder = this.selectionContainer();

    $placeholder.html(this.display(placeholder));
    $placeholder.addClass('select2-selection__placeholder')
                .removeClass('select2-selection__choice');

    return $placeholder;
  };

  Placeholder.prototype.update = function (decorated, data) {
    var singlePlaceholder = (
      data.length == 1 && data[0].id != this.placeholder.id
    );
    var multipleSelections = data.length > 1;

    if (multipleSelections || singlePlaceholder) {
      return decorated.call(this, data);
    }

    this.clear();

    var $placeholder = this.createPlaceholder(this.placeholder);

    this.$selection.find('.select2-selection__rendered').append($placeholder);
  };

  return Placeholder;
});

S2.define('select2/selection/allowClear',[
  'jquery',
  '../keys'
], function ($, KEYS) {
  function AllowClear () { }

  AllowClear.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    if (this.placeholder == null) {
      if (this.options.get('debug') && window.console && console.error) {
        console.error(
          'Select2: The `allowClear` option should be used in combination ' +
          'with the `placeholder` option.'
        );
      }
    }

    this.$selection.on('mousedown', '.select2-selection__clear',
      function (evt) {
        self._handleClear(evt);
    });

    container.on('keypress', function (evt) {
      self._handleKeyboardClear(evt, container);
    });
  };

  AllowClear.prototype._handleClear = function (_, evt) {
    // Ignore the event if it is disabled
    if (this.options.get('disabled')) {
      return;
    }

    var $clear = this.$selection.find('.select2-selection__clear');

    // Ignore the event if nothing has been selected
    if ($clear.length === 0) {
      return;
    }

    evt.stopPropagation();

    var data = $clear.data('data');

    for (var d = 0; d < data.length; d++) {
      var unselectData = {
        data: data[d]
      };

      // Trigger the `unselect` event, so people can prevent it from being
      // cleared.
      this.trigger('unselect', unselectData);

      // If the event was prevented, don't clear it out.
      if (unselectData.prevented) {
        return;
      }
    }

    this.$element.val(this.placeholder.id).trigger('change');

    this.trigger('toggle', {});
  };

  AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
    if (container.isOpen()) {
      return;
    }

    if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
      this._handleClear(evt);
    }
  };

  AllowClear.prototype.update = function (decorated, data) {
    decorated.call(this, data);

    if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
        data.length === 0) {
      return;
    }

    var $remove = $(
      '<span class="select2-selection__clear">' +
        '&times;' +
      '</span>'
    );
    $remove.data('data', data);

    this.$selection.find('.select2-selection__rendered').prepend($remove);
  };

  return AllowClear;
});

S2.define('select2/selection/search',[
  'jquery',
  '../utils',
  '../keys'
], function ($, Utils, KEYS) {
  function Search (decorated, $element, options) {
    decorated.call(this, $element, options);
  }

  Search.prototype.render = function (decorated) {
    var $search = $(
      '<li class="select2-search select2-search--inline">' +
        '<input class="select2-search__field" type="search" tabindex="-1"' +
        ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
        ' spellcheck="false" role="textbox" />' +
      '</li>'
    );

    this.$searchContainer = $search;
    this.$search = $search.find('input');

    var $rendered = decorated.call(this);

    this._transferTabIndex();

    return $rendered;
  };

  Search.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('open', function () {
      self.$search.trigger('focus');
    });

    container.on('close', function () {
      self.$search.val('');
      self.$search.trigger('focus');
    });

    container.on('enable', function () {
      self.$search.prop('disabled', false);

      self._transferTabIndex();
    });

    container.on('disable', function () {
      self.$search.prop('disabled', true);
    });

    container.on('focus', function (evt) {
      self.$search.trigger('focus');
    });

    this.$selection.on('focusin', '.select2-search--inline', function (evt) {
      self.trigger('focus', evt);
    });

    this.$selection.on('focusout', '.select2-search--inline', function (evt) {
      self._handleBlur(evt);
    });

    this.$selection.on('keydown', '.select2-search--inline', function (evt) {
      evt.stopPropagation();

      self.trigger('keypress', evt);

      self._keyUpPrevented = evt.isDefaultPrevented();

      var key = evt.which;

      if (key === KEYS.BACKSPACE && self.$search.val() === '') {
        var $previousChoice = self.$searchContainer
          .prev('.select2-selection__choice');

        if ($previousChoice.length > 0) {
          var item = $previousChoice.data('data');

          self.searchRemoveChoice(item);

          evt.preventDefault();
        }
      }
    });

    // Workaround for browsers which do not support the `input` event
    // This will prevent double-triggering of events for browsers which support
    // both the `keyup` and `input` events.
    this.$selection.on(
      'input.searchcheck',
      '.select2-search--inline',
      function (evt) {
        // Try to detect the IE version should the `documentMode` property that
        // is stored on the document. This is only implemented in IE and is
        // slightly cleaner than doing a user agent check.
        // This property is not available in Edge, but Edge also doesn't have
        // this bug.
        var msie = document.documentMode;

        // IE will trigger the `input` event when a placeholder is used on a
        // search box. To get around this issue, we are forced to ignore all
        // `input` events in IE and keep using `keyup`.
        if (msie && msie <= 11) {
          self.$selection.off('input.search input.searchcheck');
          return;
        }

        // Unbind the duplicated `keyup` event
        self.$selection.off('keyup.search');
      }
    );

    this.$selection.on(
      'keyup.search input.search',
      '.select2-search--inline',
      function (evt) {
        var key = evt.which;

        // We can freely ignore events from modifier keys
        if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
          return;
        }

        // Tabbing will be handled during the `keydown` phase
        if (key == KEYS.TAB) {
          return;
        }

        self.handleSearch(evt);
      }
    );
  };

  /**
   * This method will transfer the tabindex attribute from the rendered
   * selection to the search box. This allows for the search box to be used as
   * the primary focus instead of the selection container.
   *
   * @private
   */
  Search.prototype._transferTabIndex = function (decorated) {
    this.$search.attr('tabindex', this.$selection.attr('tabindex'));
    this.$selection.attr('tabindex', '-1');
  };

  Search.prototype.createPlaceholder = function (decorated, placeholder) {
    this.$search.attr('placeholder', placeholder.text);
  };

  Search.prototype.update = function (decorated, data) {
    var searchHadFocus = this.$search[0] == document.activeElement;

    this.$search.attr('placeholder', '');

    decorated.call(this, data);

    this.$selection.find('.select2-selection__rendered')
                   .append(this.$searchContainer);

    this.resizeSearch();
    if (searchHadFocus) {
      this.$search.focus();
    }
  };

  Search.prototype.handleSearch = function () {
    this.resizeSearch();

    if (!this._keyUpPrevented) {
      var input = this.$search.val();

      this.trigger('query', {
        term: input
      });
    }

    this._keyUpPrevented = false;
  };

  Search.prototype.searchRemoveChoice = function (decorated, item) {
    this.trigger('unselect', {
      data: item
    });

    this.trigger('open', {});

    this.$search.val(item.text + ' ');
  };

  Search.prototype.resizeSearch = function () {
    this.$search.css('width', '25px');

    var width = '';

    if (this.$search.attr('placeholder') !== '') {
      width = this.$selection.find('.select2-selection__rendered').innerWidth();
    } else {
      var minimumWidth = this.$search.val().length + 1;

      width = (minimumWidth * 0.75) + 'em';
    }

    this.$search.css('width', width);
  };

  return Search;
});

S2.define('select2/selection/eventRelay',[
  'jquery'
], function ($) {
  function EventRelay () { }

  EventRelay.prototype.bind = function (decorated, container, $container) {
    var self = this;
    var relayEvents = [
      'open', 'opening',
      'close', 'closing',
      'select', 'selecting',
      'unselect', 'unselecting'
    ];

    var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];

    decorated.call(this, container, $container);

    container.on('*', function (name, params) {
      // Ignore events that should not be relayed
      if ($.inArray(name, relayEvents) === -1) {
        return;
      }

      // The parameters should always be an object
      params = params || {};

      // Generate the jQuery event for the Select2 event
      var evt = $.Event('select2:' + name, {
        params: params
      });

      self.$element.trigger(evt);

      // Only handle preventable events if it was one
      if ($.inArray(name, preventableEvents) === -1) {
        return;
      }

      params.prevented = evt.isDefaultPrevented();
    });
  };

  return EventRelay;
});

S2.define('select2/translation',[
  'jquery',
  'require'
], function ($, require) {
  function Translation (dict) {
    this.dict = dict || {};
  }

  Translation.prototype.all = function () {
    return this.dict;
  };

  Translation.prototype.get = function (key) {
    return this.dict[key];
  };

  Translation.prototype.extend = function (translation) {
    this.dict = $.extend({}, translation.all(), this.dict);
  };

  // Static functions

  Translation._cache = {};

  Translation.loadPath = function (path) {
    if (!(path in Translation._cache)) {
      var translations = require(path);

      Translation._cache[path] = translations;
    }

    return new Translation(Translation._cache[path]);
  };

  return Translation;
});

S2.define('select2/diacritics',[

], function () {
  var diacritics = {
    '\u24B6': 'A',
    '\uFF21': 'A',
    '\u00C0': 'A',
    '\u00C1': 'A',
    '\u00C2': 'A',
    '\u1EA6': 'A',
    '\u1EA4': 'A',
    '\u1EAA': 'A',
    '\u1EA8': 'A',
    '\u00C3': 'A',
    '\u0100': 'A',
    '\u0102': 'A',
    '\u1EB0': 'A',
    '\u1EAE': 'A',
    '\u1EB4': 'A',
    '\u1EB2': 'A',
    '\u0226': 'A',
    '\u01E0': 'A',
    '\u00C4': 'A',
    '\u01DE': 'A',
    '\u1EA2': 'A',
    '\u00C5': 'A',
    '\u01FA': 'A',
    '\u01CD': 'A',
    '\u0200': 'A',
    '\u0202': 'A',
    '\u1EA0': 'A',
    '\u1EAC': 'A',
    '\u1EB6': 'A',
    '\u1E00': 'A',
    '\u0104': 'A',
    '\u023A': 'A',
    '\u2C6F': 'A',
    '\uA732': 'AA',
    '\u00C6': 'AE',
    '\u01FC': 'AE',
    '\u01E2': 'AE',
    '\uA734': 'AO',
    '\uA736': 'AU',
    '\uA738': 'AV',
    '\uA73A': 'AV',
    '\uA73C': 'AY',
    '\u24B7': 'B',
    '\uFF22': 'B',
    '\u1E02': 'B',
    '\u1E04': 'B',
    '\u1E06': 'B',
    '\u0243': 'B',
    '\u0182': 'B',
    '\u0181': 'B',
    '\u24B8': 'C',
    '\uFF23': 'C',
    '\u0106': 'C',
    '\u0108': 'C',
    '\u010A': 'C',
    '\u010C': 'C',
    '\u00C7': 'C',
    '\u1E08': 'C',
    '\u0187': 'C',
    '\u023B': 'C',
    '\uA73E': 'C',
    '\u24B9': 'D',
    '\uFF24': 'D',
    '\u1E0A': 'D',
    '\u010E': 'D',
    '\u1E0C': 'D',
    '\u1E10': 'D',
    '\u1E12': 'D',
    '\u1E0E': 'D',
    '\u0110': 'D',
    '\u018B': 'D',
    '\u018A': 'D',
    '\u0189': 'D',
    '\uA779': 'D',
    '\u01F1': 'DZ',
    '\u01C4': 'DZ',
    '\u01F2': 'Dz',
    '\u01C5': 'Dz',
    '\u24BA': 'E',
    '\uFF25': 'E',
    '\u00C8': 'E',
    '\u00C9': 'E',
    '\u00CA': 'E',
    '\u1EC0': 'E',
    '\u1EBE': 'E',
    '\u1EC4': 'E',
    '\u1EC2': 'E',
    '\u1EBC': 'E',
    '\u0112': 'E',
    '\u1E14': 'E',
    '\u1E16': 'E',
    '\u0114': 'E',
    '\u0116': 'E',
    '\u00CB': 'E',
    '\u1EBA': 'E',
    '\u011A': 'E',
    '\u0204': 'E',
    '\u0206': 'E',
    '\u1EB8': 'E',
    '\u1EC6': 'E',
    '\u0228': 'E',
    '\u1E1C': 'E',
    '\u0118': 'E',
    '\u1E18': 'E',
    '\u1E1A': 'E',
    '\u0190': 'E',
    '\u018E': 'E',
    '\u24BB': 'F',
    '\uFF26': 'F',
    '\u1E1E': 'F',
    '\u0191': 'F',
    '\uA77B': 'F',
    '\u24BC': 'G',
    '\uFF27': 'G',
    '\u01F4': 'G',
    '\u011C': 'G',
    '\u1E20': 'G',
    '\u011E': 'G',
    '\u0120': 'G',
    '\u01E6': 'G',
    '\u0122': 'G',
    '\u01E4': 'G',
    '\u0193': 'G',
    '\uA7A0': 'G',
    '\uA77D': 'G',
    '\uA77E': 'G',
    '\u24BD': 'H',
    '\uFF28': 'H',
    '\u0124': 'H',
    '\u1E22': 'H',
    '\u1E26': 'H',
    '\u021E': 'H',
    '\u1E24': 'H',
    '\u1E28': 'H',
    '\u1E2A': 'H',
    '\u0126': 'H',
    '\u2C67': 'H',
    '\u2C75': 'H',
    '\uA78D': 'H',
    '\u24BE': 'I',
    '\uFF29': 'I',
    '\u00CC': 'I',
    '\u00CD': 'I',
    '\u00CE': 'I',
    '\u0128': 'I',
    '\u012A': 'I',
    '\u012C': 'I',
    '\u0130': 'I',
    '\u00CF': 'I',
    '\u1E2E': 'I',
    '\u1EC8': 'I',
    '\u01CF': 'I',
    '\u0208': 'I',
    '\u020A': 'I',
    '\u1ECA': 'I',
    '\u012E': 'I',
    '\u1E2C': 'I',
    '\u0197': 'I',
    '\u24BF': 'J',
    '\uFF2A': 'J',
    '\u0134': 'J',
    '\u0248': 'J',
    '\u24C0': 'K',
    '\uFF2B': 'K',
    '\u1E30': 'K',
    '\u01E8': 'K',
    '\u1E32': 'K',
    '\u0136': 'K',
    '\u1E34': 'K',
    '\u0198': 'K',
    '\u2C69': 'K',
    '\uA740': 'K',
    '\uA742': 'K',
    '\uA744': 'K',
    '\uA7A2': 'K',
    '\u24C1': 'L',
    '\uFF2C': 'L',
    '\u013F': 'L',
    '\u0139': 'L',
    '\u013D': 'L',
    '\u1E36': 'L',
    '\u1E38': 'L',
    '\u013B': 'L',
    '\u1E3C': 'L',
    '\u1E3A': 'L',
    '\u0141': 'L',
    '\u023D': 'L',
    '\u2C62': 'L',
    '\u2C60': 'L',
    '\uA748': 'L',
    '\uA746': 'L',
    '\uA780': 'L',
    '\u01C7': 'LJ',
    '\u01C8': 'Lj',
    '\u24C2': 'M',
    '\uFF2D': 'M',
    '\u1E3E': 'M',
    '\u1E40': 'M',
    '\u1E42': 'M',
    '\u2C6E': 'M',
    '\u019C': 'M',
    '\u24C3': 'N',
    '\uFF2E': 'N',
    '\u01F8': 'N',
    '\u0143': 'N',
    '\u00D1': 'N',
    '\u1E44': 'N',
    '\u0147': 'N',
    '\u1E46': 'N',
    '\u0145': 'N',
    '\u1E4A': 'N',
    '\u1E48': 'N',
    '\u0220': 'N',
    '\u019D': 'N',
    '\uA790': 'N',
    '\uA7A4': 'N',
    '\u01CA': 'NJ',
    '\u01CB': 'Nj',
    '\u24C4': 'O',
    '\uFF2F': 'O',
    '\u00D2': 'O',
    '\u00D3': 'O',
    '\u00D4': 'O',
    '\u1ED2': 'O',
    '\u1ED0': 'O',
    '\u1ED6': 'O',
    '\u1ED4': 'O',
    '\u00D5': 'O',
    '\u1E4C': 'O',
    '\u022C': 'O',
    '\u1E4E': 'O',
    '\u014C': 'O',
    '\u1E50': 'O',
    '\u1E52': 'O',
    '\u014E': 'O',
    '\u022E': 'O',
    '\u0230': 'O',
    '\u00D6': 'O',
    '\u022A': 'O',
    '\u1ECE': 'O',
    '\u0150': 'O',
    '\u01D1': 'O',
    '\u020C': 'O',
    '\u020E': 'O',
    '\u01A0': 'O',
    '\u1EDC': 'O',
    '\u1EDA': 'O',
    '\u1EE0': 'O',
    '\u1EDE': 'O',
    '\u1EE2': 'O',
    '\u1ECC': 'O',
    '\u1ED8': 'O',
    '\u01EA': 'O',
    '\u01EC': 'O',
    '\u00D8': 'O',
    '\u01FE': 'O',
    '\u0186': 'O',
    '\u019F': 'O',
    '\uA74A': 'O',
    '\uA74C': 'O',
    '\u01A2': 'OI',
    '\uA74E': 'OO',
    '\u0222': 'OU',
    '\u24C5': 'P',
    '\uFF30': 'P',
    '\u1E54': 'P',
    '\u1E56': 'P',
    '\u01A4': 'P',
    '\u2C63': 'P',
    '\uA750': 'P',
    '\uA752': 'P',
    '\uA754': 'P',
    '\u24C6': 'Q',
    '\uFF31': 'Q',
    '\uA756': 'Q',
    '\uA758': 'Q',
    '\u024A': 'Q',
    '\u24C7': 'R',
    '\uFF32': 'R',
    '\u0154': 'R',
    '\u1E58': 'R',
    '\u0158': 'R',
    '\u0210': 'R',
    '\u0212': 'R',
    '\u1E5A': 'R',
    '\u1E5C': 'R',
    '\u0156': 'R',
    '\u1E5E': 'R',
    '\u024C': 'R',
    '\u2C64': 'R',
    '\uA75A': 'R',
    '\uA7A6': 'R',
    '\uA782': 'R',
    '\u24C8': 'S',
    '\uFF33': 'S',
    '\u1E9E': 'S',
    '\u015A': 'S',
    '\u1E64': 'S',
    '\u015C': 'S',
    '\u1E60': 'S',
    '\u0160': 'S',
    '\u1E66': 'S',
    '\u1E62': 'S',
    '\u1E68': 'S',
    '\u0218': 'S',
    '\u015E': 'S',
    '\u2C7E': 'S',
    '\uA7A8': 'S',
    '\uA784': 'S',
    '\u24C9': 'T',
    '\uFF34': 'T',
    '\u1E6A': 'T',
    '\u0164': 'T',
    '\u1E6C': 'T',
    '\u021A': 'T',
    '\u0162': 'T',
    '\u1E70': 'T',
    '\u1E6E': 'T',
    '\u0166': 'T',
    '\u01AC': 'T',
    '\u01AE': 'T',
    '\u023E': 'T',
    '\uA786': 'T',
    '\uA728': 'TZ',
    '\u24CA': 'U',
    '\uFF35': 'U',
    '\u00D9': 'U',
    '\u00DA': 'U',
    '\u00DB': 'U',
    '\u0168': 'U',
    '\u1E78': 'U',
    '\u016A': 'U',
    '\u1E7A': 'U',
    '\u016C': 'U',
    '\u00DC': 'U',
    '\u01DB': 'U',
    '\u01D7': 'U',
    '\u01D5': 'U',
    '\u01D9': 'U',
    '\u1EE6': 'U',
    '\u016E': 'U',
    '\u0170': 'U',
    '\u01D3': 'U',
    '\u0214': 'U',
    '\u0216': 'U',
    '\u01AF': 'U',
    '\u1EEA': 'U',
    '\u1EE8': 'U',
    '\u1EEE': 'U',
    '\u1EEC': 'U',
    '\u1EF0': 'U',
    '\u1EE4': 'U',
    '\u1E72': 'U',
    '\u0172': 'U',
    '\u1E76': 'U',
    '\u1E74': 'U',
    '\u0244': 'U',
    '\u24CB': 'V',
    '\uFF36': 'V',
    '\u1E7C': 'V',
    '\u1E7E': 'V',
    '\u01B2': 'V',
    '\uA75E': 'V',
    '\u0245': 'V',
    '\uA760': 'VY',
    '\u24CC': 'W',
    '\uFF37': 'W',
    '\u1E80': 'W',
    '\u1E82': 'W',
    '\u0174': 'W',
    '\u1E86': 'W',
    '\u1E84': 'W',
    '\u1E88': 'W',
    '\u2C72': 'W',
    '\u24CD': 'X',
    '\uFF38': 'X',
    '\u1E8A': 'X',
    '\u1E8C': 'X',
    '\u24CE': 'Y',
    '\uFF39': 'Y',
    '\u1EF2': 'Y',
    '\u00DD': 'Y',
    '\u0176': 'Y',
    '\u1EF8': 'Y',
    '\u0232': 'Y',
    '\u1E8E': 'Y',
    '\u0178': 'Y',
    '\u1EF6': 'Y',
    '\u1EF4': 'Y',
    '\u01B3': 'Y',
    '\u024E': 'Y',
    '\u1EFE': 'Y',
    '\u24CF': 'Z',
    '\uFF3A': 'Z',
    '\u0179': 'Z',
    '\u1E90': 'Z',
    '\u017B': 'Z',
    '\u017D': 'Z',
    '\u1E92': 'Z',
    '\u1E94': 'Z',
    '\u01B5': 'Z',
    '\u0224': 'Z',
    '\u2C7F': 'Z',
    '\u2C6B': 'Z',
    '\uA762': 'Z',
    '\u24D0': 'a',
    '\uFF41': 'a',
    '\u1E9A': 'a',
    '\u00E0': 'a',
    '\u00E1': 'a',
    '\u00E2': 'a',
    '\u1EA7': 'a',
    '\u1EA5': 'a',
    '\u1EAB': 'a',
    '\u1EA9': 'a',
    '\u00E3': 'a',
    '\u0101': 'a',
    '\u0103': 'a',
    '\u1EB1': 'a',
    '\u1EAF': 'a',
    '\u1EB5': 'a',
    '\u1EB3': 'a',
    '\u0227': 'a',
    '\u01E1': 'a',
    '\u00E4': 'a',
    '\u01DF': 'a',
    '\u1EA3': 'a',
    '\u00E5': 'a',
    '\u01FB': 'a',
    '\u01CE': 'a',
    '\u0201': 'a',
    '\u0203': 'a',
    '\u1EA1': 'a',
    '\u1EAD': 'a',
    '\u1EB7': 'a',
    '\u1E01': 'a',
    '\u0105': 'a',
    '\u2C65': 'a',
    '\u0250': 'a',
    '\uA733': 'aa',
    '\u00E6': 'ae',
    '\u01FD': 'ae',
    '\u01E3': 'ae',
    '\uA735': 'ao',
    '\uA737': 'au',
    '\uA739': 'av',
    '\uA73B': 'av',
    '\uA73D': 'ay',
    '\u24D1': 'b',
    '\uFF42': 'b',
    '\u1E03': 'b',
    '\u1E05': 'b',
    '\u1E07': 'b',
    '\u0180': 'b',
    '\u0183': 'b',
    '\u0253': 'b',
    '\u24D2': 'c',
    '\uFF43': 'c',
    '\u0107': 'c',
    '\u0109': 'c',
    '\u010B': 'c',
    '\u010D': 'c',
    '\u00E7': 'c',
    '\u1E09': 'c',
    '\u0188': 'c',
    '\u023C': 'c',
    '\uA73F': 'c',
    '\u2184': 'c',
    '\u24D3': 'd',
    '\uFF44': 'd',
    '\u1E0B': 'd',
    '\u010F': 'd',
    '\u1E0D': 'd',
    '\u1E11': 'd',
    '\u1E13': 'd',
    '\u1E0F': 'd',
    '\u0111': 'd',
    '\u018C': 'd',
    '\u0256': 'd',
    '\u0257': 'd',
    '\uA77A': 'd',
    '\u01F3': 'dz',
    '\u01C6': 'dz',
    '\u24D4': 'e',
    '\uFF45': 'e',
    '\u00E8': 'e',
    '\u00E9': 'e',
    '\u00EA': 'e',
    '\u1EC1': 'e',
    '\u1EBF': 'e',
    '\u1EC5': 'e',
    '\u1EC3': 'e',
    '\u1EBD': 'e',
    '\u0113': 'e',
    '\u1E15': 'e',
    '\u1E17': 'e',
    '\u0115': 'e',
    '\u0117': 'e',
    '\u00EB': 'e',
    '\u1EBB': 'e',
    '\u011B': 'e',
    '\u0205': 'e',
    '\u0207': 'e',
    '\u1EB9': 'e',
    '\u1EC7': 'e',
    '\u0229': 'e',
    '\u1E1D': 'e',
    '\u0119': 'e',
    '\u1E19': 'e',
    '\u1E1B': 'e',
    '\u0247': 'e',
    '\u025B': 'e',
    '\u01DD': 'e',
    '\u24D5': 'f',
    '\uFF46': 'f',
    '\u1E1F': 'f',
    '\u0192': 'f',
    '\uA77C': 'f',
    '\u24D6': 'g',
    '\uFF47': 'g',
    '\u01F5': 'g',
    '\u011D': 'g',
    '\u1E21': 'g',
    '\u011F': 'g',
    '\u0121': 'g',
    '\u01E7': 'g',
    '\u0123': 'g',
    '\u01E5': 'g',
    '\u0260': 'g',
    '\uA7A1': 'g',
    '\u1D79': 'g',
    '\uA77F': 'g',
    '\u24D7': 'h',
    '\uFF48': 'h',
    '\u0125': 'h',
    '\u1E23': 'h',
    '\u1E27': 'h',
    '\u021F': 'h',
    '\u1E25': 'h',
    '\u1E29': 'h',
    '\u1E2B': 'h',
    '\u1E96': 'h',
    '\u0127': 'h',
    '\u2C68': 'h',
    '\u2C76': 'h',
    '\u0265': 'h',
    '\u0195': 'hv',
    '\u24D8': 'i',
    '\uFF49': 'i',
    '\u00EC': 'i',
    '\u00ED': 'i',
    '\u00EE': 'i',
    '\u0129': 'i',
    '\u012B': 'i',
    '\u012D': 'i',
    '\u00EF': 'i',
    '\u1E2F': 'i',
    '\u1EC9': 'i',
    '\u01D0': 'i',
    '\u0209': 'i',
    '\u020B': 'i',
    '\u1ECB': 'i',
    '\u012F': 'i',
    '\u1E2D': 'i',
    '\u0268': 'i',
    '\u0131': 'i',
    '\u24D9': 'j',
    '\uFF4A': 'j',
    '\u0135': 'j',
    '\u01F0': 'j',
    '\u0249': 'j',
    '\u24DA': 'k',
    '\uFF4B': 'k',
    '\u1E31': 'k',
    '\u01E9': 'k',
    '\u1E33': 'k',
    '\u0137': 'k',
    '\u1E35': 'k',
    '\u0199': 'k',
    '\u2C6A': 'k',
    '\uA741': 'k',
    '\uA743': 'k',
    '\uA745': 'k',
    '\uA7A3': 'k',
    '\u24DB': 'l',
    '\uFF4C': 'l',
    '\u0140': 'l',
    '\u013A': 'l',
    '\u013E': 'l',
    '\u1E37': 'l',
    '\u1E39': 'l',
    '\u013C': 'l',
    '\u1E3D': 'l',
    '\u1E3B': 'l',
    '\u017F': 'l',
    '\u0142': 'l',
    '\u019A': 'l',
    '\u026B': 'l',
    '\u2C61': 'l',
    '\uA749': 'l',
    '\uA781': 'l',
    '\uA747': 'l',
    '\u01C9': 'lj',
    '\u24DC': 'm',
    '\uFF4D': 'm',
    '\u1E3F': 'm',
    '\u1E41': 'm',
    '\u1E43': 'm',
    '\u0271': 'm',
    '\u026F': 'm',
    '\u24DD': 'n',
    '\uFF4E': 'n',
    '\u01F9': 'n',
    '\u0144': 'n',
    '\u00F1': 'n',
    '\u1E45': 'n',
    '\u0148': 'n',
    '\u1E47': 'n',
    '\u0146': 'n',
    '\u1E4B': 'n',
    '\u1E49': 'n',
    '\u019E': 'n',
    '\u0272': 'n',
    '\u0149': 'n',
    '\uA791': 'n',
    '\uA7A5': 'n',
    '\u01CC': 'nj',
    '\u24DE': 'o',
    '\uFF4F': 'o',
    '\u00F2': 'o',
    '\u00F3': 'o',
    '\u00F4': 'o',
    '\u1ED3': 'o',
    '\u1ED1': 'o',
    '\u1ED7': 'o',
    '\u1ED5': 'o',
    '\u00F5': 'o',
    '\u1E4D': 'o',
    '\u022D': 'o',
    '\u1E4F': 'o',
    '\u014D': 'o',
    '\u1E51': 'o',
    '\u1E53': 'o',
    '\u014F': 'o',
    '\u022F': 'o',
    '\u0231': 'o',
    '\u00F6': 'o',
    '\u022B': 'o',
    '\u1ECF': 'o',
    '\u0151': 'o',
    '\u01D2': 'o',
    '\u020D': 'o',
    '\u020F': 'o',
    '\u01A1': 'o',
    '\u1EDD': 'o',
    '\u1EDB': 'o',
    '\u1EE1': 'o',
    '\u1EDF': 'o',
    '\u1EE3': 'o',
    '\u1ECD': 'o',
    '\u1ED9': 'o',
    '\u01EB': 'o',
    '\u01ED': 'o',
    '\u00F8': 'o',
    '\u01FF': 'o',
    '\u0254': 'o',
    '\uA74B': 'o',
    '\uA74D': 'o',
    '\u0275': 'o',
    '\u01A3': 'oi',
    '\u0223': 'ou',
    '\uA74F': 'oo',
    '\u24DF': 'p',
    '\uFF50': 'p',
    '\u1E55': 'p',
    '\u1E57': 'p',
    '\u01A5': 'p',
    '\u1D7D': 'p',
    '\uA751': 'p',
    '\uA753': 'p',
    '\uA755': 'p',
    '\u24E0': 'q',
    '\uFF51': 'q',
    '\u024B': 'q',
    '\uA757': 'q',
    '\uA759': 'q',
    '\u24E1': 'r',
    '\uFF52': 'r',
    '\u0155': 'r',
    '\u1E59': 'r',
    '\u0159': 'r',
    '\u0211': 'r',
    '\u0213': 'r',
    '\u1E5B': 'r',
    '\u1E5D': 'r',
    '\u0157': 'r',
    '\u1E5F': 'r',
    '\u024D': 'r',
    '\u027D': 'r',
    '\uA75B': 'r',
    '\uA7A7': 'r',
    '\uA783': 'r',
    '\u24E2': 's',
    '\uFF53': 's',
    '\u00DF': 's',
    '\u015B': 's',
    '\u1E65': 's',
    '\u015D': 's',
    '\u1E61': 's',
    '\u0161': 's',
    '\u1E67': 's',
    '\u1E63': 's',
    '\u1E69': 's',
    '\u0219': 's',
    '\u015F': 's',
    '\u023F': 's',
    '\uA7A9': 's',
    '\uA785': 's',
    '\u1E9B': 's',
    '\u24E3': 't',
    '\uFF54': 't',
    '\u1E6B': 't',
    '\u1E97': 't',
    '\u0165': 't',
    '\u1E6D': 't',
    '\u021B': 't',
    '\u0163': 't',
    '\u1E71': 't',
    '\u1E6F': 't',
    '\u0167': 't',
    '\u01AD': 't',
    '\u0288': 't',
    '\u2C66': 't',
    '\uA787': 't',
    '\uA729': 'tz',
    '\u24E4': 'u',
    '\uFF55': 'u',
    '\u00F9': 'u',
    '\u00FA': 'u',
    '\u00FB': 'u',
    '\u0169': 'u',
    '\u1E79': 'u',
    '\u016B': 'u',
    '\u1E7B': 'u',
    '\u016D': 'u',
    '\u00FC': 'u',
    '\u01DC': 'u',
    '\u01D8': 'u',
    '\u01D6': 'u',
    '\u01DA': 'u',
    '\u1EE7': 'u',
    '\u016F': 'u',
    '\u0171': 'u',
    '\u01D4': 'u',
    '\u0215': 'u',
    '\u0217': 'u',
    '\u01B0': 'u',
    '\u1EEB': 'u',
    '\u1EE9': 'u',
    '\u1EEF': 'u',
    '\u1EED': 'u',
    '\u1EF1': 'u',
    '\u1EE5': 'u',
    '\u1E73': 'u',
    '\u0173': 'u',
    '\u1E77': 'u',
    '\u1E75': 'u',
    '\u0289': 'u',
    '\u24E5': 'v',
    '\uFF56': 'v',
    '\u1E7D': 'v',
    '\u1E7F': 'v',
    '\u028B': 'v',
    '\uA75F': 'v',
    '\u028C': 'v',
    '\uA761': 'vy',
    '\u24E6': 'w',
    '\uFF57': 'w',
    '\u1E81': 'w',
    '\u1E83': 'w',
    '\u0175': 'w',
    '\u1E87': 'w',
    '\u1E85': 'w',
    '\u1E98': 'w',
    '\u1E89': 'w',
    '\u2C73': 'w',
    '\u24E7': 'x',
    '\uFF58': 'x',
    '\u1E8B': 'x',
    '\u1E8D': 'x',
    '\u24E8': 'y',
    '\uFF59': 'y',
    '\u1EF3': 'y',
    '\u00FD': 'y',
    '\u0177': 'y',
    '\u1EF9': 'y',
    '\u0233': 'y',
    '\u1E8F': 'y',
    '\u00FF': 'y',
    '\u1EF7': 'y',
    '\u1E99': 'y',
    '\u1EF5': 'y',
    '\u01B4': 'y',
    '\u024F': 'y',
    '\u1EFF': 'y',
    '\u24E9': 'z',
    '\uFF5A': 'z',
    '\u017A': 'z',
    '\u1E91': 'z',
    '\u017C': 'z',
    '\u017E': 'z',
    '\u1E93': 'z',
    '\u1E95': 'z',
    '\u01B6': 'z',
    '\u0225': 'z',
    '\u0240': 'z',
    '\u2C6C': 'z',
    '\uA763': 'z',
    '\u0386': '\u0391',
    '\u0388': '\u0395',
    '\u0389': '\u0397',
    '\u038A': '\u0399',
    '\u03AA': '\u0399',
    '\u038C': '\u039F',
    '\u038E': '\u03A5',
    '\u03AB': '\u03A5',
    '\u038F': '\u03A9',
    '\u03AC': '\u03B1',
    '\u03AD': '\u03B5',
    '\u03AE': '\u03B7',
    '\u03AF': '\u03B9',
    '\u03CA': '\u03B9',
    '\u0390': '\u03B9',
    '\u03CC': '\u03BF',
    '\u03CD': '\u03C5',
    '\u03CB': '\u03C5',
    '\u03B0': '\u03C5',
    '\u03C9': '\u03C9',
    '\u03C2': '\u03C3'
  };

  return diacritics;
});

S2.define('select2/data/base',[
  '../utils'
], function (Utils) {
  function BaseAdapter ($element, options) {
    BaseAdapter.__super__.constructor.call(this);
  }

  Utils.Extend(BaseAdapter, Utils.Observable);

  BaseAdapter.prototype.current = function (callback) {
    throw new Error('The `current` method must be defined in child classes.');
  };

  BaseAdapter.prototype.query = function (params, callback) {
    throw new Error('The `query` method must be defined in child classes.');
  };

  BaseAdapter.prototype.bind = function (container, $container) {
    // Can be implemented in subclasses
  };

  BaseAdapter.prototype.destroy = function () {
    // Can be implemented in subclasses
  };

  BaseAdapter.prototype.generateResultId = function (container, data) {
    var id = container.id + '-result-';

    id += Utils.generateChars(4);

    if (data.id != null) {
      id += '-' + data.id.toString();
    } else {
      id += '-' + Utils.generateChars(4);
    }
    return id;
  };

  return BaseAdapter;
});

S2.define('select2/data/select',[
  './base',
  '../utils',
  'jquery'
], function (BaseAdapter, Utils, $) {
  function SelectAdapter ($element, options) {
    this.$element = $element;
    this.options = options;

    SelectAdapter.__super__.constructor.call(this);
  }

  Utils.Extend(SelectAdapter, BaseAdapter);

  SelectAdapter.prototype.current = function (callback) {
    var data = [];
    var self = this;

    this.$element.find(':selected').each(function () {
      var $option = $(this);

      var option = self.item($option);

      data.push(option);
    });

    callback(data);
  };

  SelectAdapter.prototype.select = function (data) {
    var self = this;

    data.selected = true;

    // If data.element is a DOM node, use it instead
    if ($(data.element).is('option')) {
      data.element.selected = true;

      this.$element.trigger('change');

      return;
    }

    if (this.$element.prop('multiple')) {
      this.current(function (currentData) {
        var val = [];

        data = [data];
        data.push.apply(data, currentData);

        for (var d = 0; d < data.length; d++) {
          var id = data[d].id;

          if ($.inArray(id, val) === -1) {
            val.push(id);
          }
        }

        self.$element.val(val);
        self.$element.trigger('change');
      });
    } else {
      var val = data.id;

      this.$element.val(val);
      this.$element.trigger('change');
    }
  };

  SelectAdapter.prototype.unselect = function (data) {
    var self = this;

    if (!this.$element.prop('multiple')) {
      return;
    }

    data.selected = false;

    if ($(data.element).is('option')) {
      data.element.selected = false;

      this.$element.trigger('change');

      return;
    }

    this.current(function (currentData) {
      var val = [];

      for (var d = 0; d < currentData.length; d++) {
        var id = currentData[d].id;

        if (id !== data.id && $.inArray(id, val) === -1) {
          val.push(id);
        }
      }

      self.$element.val(val);

      self.$element.trigger('change');
    });
  };

  SelectAdapter.prototype.bind = function (container, $container) {
    var self = this;

    this.container = container;

    container.on('select', function (params) {
      self.select(params.data);
    });

    container.on('unselect', function (params) {
      self.unselect(params.data);
    });
  };

  SelectAdapter.prototype.destroy = function () {
    // Remove anything added to child elements
    this.$element.find('*').each(function () {
      // Remove any custom data set by Select2
      $.removeData(this, 'data');
    });
  };

  SelectAdapter.prototype.query = function (params, callback) {
    var data = [];
    var self = this;

    var $options = this.$element.children();

    $options.each(function () {
      var $option = $(this);

      if (!$option.is('option') && !$option.is('optgroup')) {
        return;
      }

      var option = self.item($option);

      var matches = self.matches(params, option);

      if (matches !== null) {
        data.push(matches);
      }
    });

    callback({
      results: data
    });
  };

  SelectAdapter.prototype.addOptions = function ($options) {
    Utils.appendMany(this.$element, $options);
  };

  SelectAdapter.prototype.option = function (data) {
    var option;

    if (data.children) {
      option = document.createElement('optgroup');
      option.label = data.text;
    } else {
      option = document.createElement('option');

      if (option.textContent !== undefined) {
        option.textContent = data.text;
      } else {
        option.innerText = data.text;
      }
    }

    if (data.id) {
      option.value = data.id;
    }

    if (data.disabled) {
      option.disabled = true;
    }

    if (data.selected) {
      option.selected = true;
    }

    if (data.title) {
      option.title = data.title;
    }

    var $option = $(option);

    var normalizedData = this._normalizeItem(data);
    normalizedData.element = option;

    // Override the option's data with the combined data
    $.data(option, 'data', normalizedData);

    return $option;
  };

  SelectAdapter.prototype.item = function ($option) {
    var data = {};

    data = $.data($option[0], 'data');

    if (data != null) {
      return data;
    }

    if ($option.is('option')) {
      data = {
        id: $option.val(),
        text: $option.text(),
        disabled: $option.prop('disabled'),
        selected: $option.prop('selected'),
        title: $option.prop('title')
      };
    } else if ($option.is('optgroup')) {
      data = {
        text: $option.prop('label'),
        children: [],
        title: $option.prop('title')
      };

      var $children = $option.children('option');
      var children = [];

      for (var c = 0; c < $children.length; c++) {
        var $child = $($children[c]);

        var child = this.item($child);

        children.push(child);
      }

      data.children = children;
    }

    data = this._normalizeItem(data);
    data.element = $option[0];

    $.data($option[0], 'data', data);

    return data;
  };

  SelectAdapter.prototype._normalizeItem = function (item) {
    if (!$.isPlainObject(item)) {
      item = {
        id: item,
        text: item
      };
    }

    item = $.extend({}, {
      text: ''
    }, item);

    var defaults = {
      selected: false,
      disabled: false
    };

    if (item.id != null) {
      item.id = item.id.toString();
    }

    if (item.text != null) {
      item.text = item.text.toString();
    }

    if (item._resultId == null && item.id && this.container != null) {
      item._resultId = this.generateResultId(this.container, item);
    }

    return $.extend({}, defaults, item);
  };

  SelectAdapter.prototype.matches = function (params, data) {
    var matcher = this.options.get('matcher');

    return matcher(params, data);
  };

  return SelectAdapter;
});

S2.define('select2/data/array',[
  './select',
  '../utils',
  'jquery'
], function (SelectAdapter, Utils, $) {
  function ArrayAdapter ($element, options) {
    var data = options.get('data') || [];

    ArrayAdapter.__super__.constructor.call(this, $element, options);

    this.addOptions(this.convertToOptions(data));
  }

  Utils.Extend(ArrayAdapter, SelectAdapter);

  ArrayAdapter.prototype.select = function (data) {
    var $option = this.$element.find('option').filter(function (i, elm) {
      return elm.value == data.id.toString();
    });

    if ($option.length === 0) {
      $option = this.option(data);

      this.addOptions($option);
    }

    ArrayAdapter.__super__.select.call(this, data);
  };

  ArrayAdapter.prototype.convertToOptions = function (data) {
    var self = this;

    var $existing = this.$element.find('option');
    var existingIds = $existing.map(function () {
      return self.item($(this)).id;
    }).get();

    var $options = [];

    // Filter out all items except for the one passed in the argument
    function onlyItem (item) {
      return function () {
        return $(this).val() == item.id;
      };
    }

    for (var d = 0; d < data.length; d++) {
      var item = this._normalizeItem(data[d]);

      // Skip items which were pre-loaded, only merge the data
      if ($.inArray(item.id, existingIds) >= 0) {
        var $existingOption = $existing.filter(onlyItem(item));

        var existingData = this.item($existingOption);
        var newData = $.extend(true, {}, existingData, item);

        var $newOption = this.option(newData);

        $existingOption.replaceWith($newOption);

        continue;
      }

      var $option = this.option(item);

      if (item.children) {
        var $children = this.convertToOptions(item.children);

        Utils.appendMany($option, $children);
      }

      $options.push($option);
    }

    return $options;
  };

  return ArrayAdapter;
});

S2.define('select2/data/ajax',[
  './array',
  '../utils',
  'jquery'
], function (ArrayAdapter, Utils, $) {
  function AjaxAdapter ($element, options) {
    this.ajaxOptions = this._applyDefaults(options.get('ajax'));

    if (this.ajaxOptions.processResults != null) {
      this.processResults = this.ajaxOptions.processResults;
    }

    AjaxAdapter.__super__.constructor.call(this, $element, options);
  }

  Utils.Extend(AjaxAdapter, ArrayAdapter);

  AjaxAdapter.prototype._applyDefaults = function (options) {
    var defaults = {
      data: function (params) {
        return {
          q: params.term
        };
      },
      transport: function (params, success, failure) {
        var $request = $.ajax(params);

        $request.then(success);
        $request.fail(failure);

        return $request;
      }
    };

    return $.extend({}, defaults, options, true);
  };

  AjaxAdapter.prototype.processResults = function (results) {
    return results;
  };

  AjaxAdapter.prototype.query = function (params, callback) {
    var matches = [];
    var self = this;

    if (this._request != null) {
      // JSONP requests cannot always be aborted
      if ($.isFunction(this._request.abort)) {
        this._request.abort();
      }

      this._request = null;
    }

    var options = $.extend({
      type: 'GET'
    }, this.ajaxOptions);

    if (typeof options.url === 'function') {
      options.url = options.url(params);
    }

    if (typeof options.data === 'function') {
      options.data = options.data(params);
    }

    function request () {
      var $request = options.transport(options, function (data) {
        var results = self.processResults(data, params);

        if (self.options.get('debug') && window.console && console.error) {
          // Check to make sure that the response included a `results` key.
          if (!results || !results.results || !$.isArray(results.results)) {
            console.error(
              'Select2: The AJAX results did not return an array in the ' +
              '`results` key of the response.'
            );
          }
        }

        callback(results);
      }, function () {
        // TODO: Handle AJAX errors
      });

      self._request = $request;
    }

    if (this.ajaxOptions.delay && params.term !== '') {
      if (this._queryTimeout) {
        window.clearTimeout(this._queryTimeout);
      }

      this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
    } else {
      request();
    }
  };

  return AjaxAdapter;
});

S2.define('select2/data/tags',[
  'jquery'
], function ($) {
  function Tags (decorated, $element, options) {
    var tags = options.get('tags');

    var createTag = options.get('createTag');

    if (createTag !== undefined) {
      this.createTag = createTag;
    }

    decorated.call(this, $element, options);

    if ($.isArray(tags)) {
      for (var t = 0; t < tags.length; t++) {
        var tag = tags[t];
        var item = this._normalizeItem(tag);

        var $option = this.option(item);

        this.$element.append($option);
      }
    }
  }

  Tags.prototype.query = function (decorated, params, callback) {
    var self = this;

    this._removeOldTags();

    if (params.term == null || params.page != null) {
      decorated.call(this, params, callback);
      return;
    }

    function wrapper (obj, child) {
      var data = obj.results;

      for (var i = 0; i < data.length; i++) {
        var option = data[i];

        var checkChildren = (
          option.children != null &&
          !wrapper({
            results: option.children
          }, true)
        );

        var checkText = option.text === params.term;

        if (checkText || checkChildren) {
          if (child) {
            return false;
          }

          obj.data = data;
          callback(obj);

          return;
        }
      }

      if (child) {
        return true;
      }

      var tag = self.createTag(params);

      if (tag != null) {
        var $option = self.option(tag);
        $option.attr('data-select2-tag', true);

        self.addOptions([$option]);

        self.insertTag(data, tag);
      }

      obj.results = data;

      callback(obj);
    }

    decorated.call(this, params, wrapper);
  };

  Tags.prototype.createTag = function (decorated, params) {
    var term = $.trim(params.term);

    if (term === '') {
      return null;
    }

    return {
      id: term,
      text: term
    };
  };

  Tags.prototype.insertTag = function (_, data, tag) {
    data.unshift(tag);
  };

  Tags.prototype._removeOldTags = function (_) {
    var tag = this._lastTag;

    var $options = this.$element.find('option[data-select2-tag]');

    $options.each(function () {
      if (this.selected) {
        return;
      }

      $(this).remove();
    });
  };

  return Tags;
});

S2.define('select2/data/tokenizer',[
  'jquery'
], function ($) {
  function Tokenizer (decorated, $element, options) {
    var tokenizer = options.get('tokenizer');

    if (tokenizer !== undefined) {
      this.tokenizer = tokenizer;
    }

    decorated.call(this, $element, options);
  }

  Tokenizer.prototype.bind = function (decorated, container, $container) {
    decorated.call(this, container, $container);

    this.$search =  container.dropdown.$search || container.selection.$search ||
      $container.find('.select2-search__field');
  };

  Tokenizer.prototype.query = function (decorated, params, callback) {
    var self = this;

    function select (data) {
      self.trigger('select', {
        data: data
      });
    }

    params.term = params.term || '';

    var tokenData = this.tokenizer(params, this.options, select);

    if (tokenData.term !== params.term) {
      // Replace the search term if we have the search box
      if (this.$search.length) {
        this.$search.val(tokenData.term);
        this.$search.focus();
      }

      params.term = tokenData.term;
    }

    decorated.call(this, params, callback);
  };

  Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
    var separators = options.get('tokenSeparators') || [];
    var term = params.term;
    var i = 0;

    var createTag = this.createTag || function (params) {
      return {
        id: params.term,
        text: params.term
      };
    };

    while (i < term.length) {
      var termChar = term[i];

      if ($.inArray(termChar, separators) === -1) {
        i++;

        continue;
      }

      var part = term.substr(0, i);
      var partParams = $.extend({}, params, {
        term: part
      });

      var data = createTag(partParams);

      if (data == null) {
        i++;
        continue;
      }

      callback(data);

      // Reset the term to not include the tokenized portion
      term = term.substr(i + 1) || '';
      i = 0;
    }

    return {
      term: term
    };
  };

  return Tokenizer;
});

S2.define('select2/data/minimumInputLength',[

], function () {
  function MinimumInputLength (decorated, $e, options) {
    this.minimumInputLength = options.get('minimumInputLength');

    decorated.call(this, $e, options);
  }

  MinimumInputLength.prototype.query = function (decorated, params, callback) {
    params.term = params.term || '';

    if (params.term.length < this.minimumInputLength) {
      this.trigger('results:message', {
        message: 'inputTooShort',
        args: {
          minimum: this.minimumInputLength,
          input: params.term,
          params: params
        }
      });

      return;
    }

    decorated.call(this, params, callback);
  };

  return MinimumInputLength;
});

S2.define('select2/data/maximumInputLength',[

], function () {
  function MaximumInputLength (decorated, $e, options) {
    this.maximumInputLength = options.get('maximumInputLength');

    decorated.call(this, $e, options);
  }

  MaximumInputLength.prototype.query = function (decorated, params, callback) {
    params.term = params.term || '';

    if (this.maximumInputLength > 0 &&
        params.term.length > this.maximumInputLength) {
      this.trigger('results:message', {
        message: 'inputTooLong',
        args: {
          maximum: this.maximumInputLength,
          input: params.term,
          params: params
        }
      });

      return;
    }

    decorated.call(this, params, callback);
  };

  return MaximumInputLength;
});

S2.define('select2/data/maximumSelectionLength',[

], function (){
  function MaximumSelectionLength (decorated, $e, options) {
    this.maximumSelectionLength = options.get('maximumSelectionLength');

    decorated.call(this, $e, options);
  }

  MaximumSelectionLength.prototype.query =
    function (decorated, params, callback) {
      var self = this;

      this.current(function (currentData) {
        var count = currentData != null ? currentData.length : 0;
        if (self.maximumSelectionLength > 0 &&
          count >= self.maximumSelectionLength) {
          self.trigger('results:message', {
            message: 'maximumSelected',
            args: {
              maximum: self.maximumSelectionLength
            }
          });
          return;
        }
        decorated.call(self, params, callback);
      });
  };

  return MaximumSelectionLength;
});

S2.define('select2/dropdown',[
  'jquery',
  './utils'
], function ($, Utils) {
  function Dropdown ($element, options) {
    this.$element = $element;
    this.options = options;

    Dropdown.__super__.constructor.call(this);
  }

  Utils.Extend(Dropdown, Utils.Observable);

  Dropdown.prototype.render = function () {
    var $dropdown = $(
      '<span class="select2-dropdown">' +
        '<span class="select2-results"></span>' +
      '</span>'
    );

    $dropdown.attr('dir', this.options.get('dir'));

    this.$dropdown = $dropdown;

    return $dropdown;
  };

  Dropdown.prototype.position = function ($dropdown, $container) {
    // Should be implmented in subclasses
  };

  Dropdown.prototype.destroy = function () {
    // Remove the dropdown from the DOM
    this.$dropdown.remove();
  };

  return Dropdown;
});

S2.define('select2/dropdown/search',[
  'jquery',
  '../utils'
], function ($, Utils) {
  function Search () { }

  Search.prototype.render = function (decorated) {
    var $rendered = decorated.call(this);

    var $search = $(
      '<span class="select2-search select2-search--dropdown">' +
        '<input class="select2-search__field" type="search" tabindex="-1"' +
        ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
        ' spellcheck="false" role="textbox" />' +
      '</span>'
    );

    this.$searchContainer = $search;
    this.$search = $search.find('input');

    $rendered.prepend($search);

    return $rendered;
  };

  Search.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    this.$search.on('keydown', function (evt) {
      self.trigger('keypress', evt);

      self._keyUpPrevented = evt.isDefaultPrevented();
    });

    // Workaround for browsers which do not support the `input` event
    // This will prevent double-triggering of events for browsers which support
    // both the `keyup` and `input` events.
    this.$search.on('input', function (evt) {
      // Unbind the duplicated `keyup` event
      $(this).off('keyup');
    });

    this.$search.on('keyup input', function (evt) {
      self.handleSearch(evt);
    });

    container.on('open', function () {
      self.$search.attr('tabindex', 0);

      self.$search.focus();

      window.setTimeout(function () {
        self.$search.focus();
      }, 0);
    });

    container.on('close', function () {
      self.$search.attr('tabindex', -1);

      self.$search.val('');
    });

    container.on('results:all', function (params) {
      if (params.query.term == null || params.query.term === '') {
        var showSearch = self.showSearch(params);

        if (showSearch) {
          self.$searchContainer.removeClass('select2-search--hide');
        } else {
          self.$searchContainer.addClass('select2-search--hide');
        }
      }
    });
  };

  Search.prototype.handleSearch = function (evt) {
    if (!this._keyUpPrevented) {
      var input = this.$search.val();

      this.trigger('query', {
        term: input
      });
    }

    this._keyUpPrevented = false;
  };

  Search.prototype.showSearch = function (_, params) {
    return true;
  };

  return Search;
});

S2.define('select2/dropdown/hidePlaceholder',[

], function () {
  function HidePlaceholder (decorated, $element, options, dataAdapter) {
    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));

    decorated.call(this, $element, options, dataAdapter);
  }

  HidePlaceholder.prototype.append = function (decorated, data) {
    data.results = this.removePlaceholder(data.results);

    decorated.call(this, data);
  };

  HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
    if (typeof placeholder === 'string') {
      placeholder = {
        id: '',
        text: placeholder
      };
    }

    return placeholder;
  };

  HidePlaceholder.prototype.removePlaceholder = function (_, data) {
    var modifiedData = data.slice(0);

    for (var d = data.length - 1; d >= 0; d--) {
      var item = data[d];

      if (this.placeholder.id === item.id) {
        modifiedData.splice(d, 1);
      }
    }

    return modifiedData;
  };

  return HidePlaceholder;
});

S2.define('select2/dropdown/infiniteScroll',[
  'jquery'
], function ($) {
  function InfiniteScroll (decorated, $element, options, dataAdapter) {
    this.lastParams = {};

    decorated.call(this, $element, options, dataAdapter);

    this.$loadingMore = this.createLoadingMore();
    this.loading = false;
  }

  InfiniteScroll.prototype.append = function (decorated, data) {
    this.$loadingMore.remove();
    this.loading = false;

    decorated.call(this, data);

    if (this.showLoadingMore(data)) {
      this.$results.append(this.$loadingMore);
    }
  };

  InfiniteScroll.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('query', function (params) {
      self.lastParams = params;
      self.loading = true;
    });

    container.on('query:append', function (params) {
      self.lastParams = params;
      self.loading = true;
    });

    this.$results.on('scroll', function () {
      var isLoadMoreVisible = $.contains(
        document.documentElement,
        self.$loadingMore[0]
      );

      if (self.loading || !isLoadMoreVisible) {
        return;
      }

      var currentOffset = self.$results.offset().top +
        self.$results.outerHeight(false);
      var loadingMoreOffset = self.$loadingMore.offset().top +
        self.$loadingMore.outerHeight(false);

      if (currentOffset + 50 >= loadingMoreOffset) {
        self.loadMore();
      }
    });
  };

  InfiniteScroll.prototype.loadMore = function () {
    this.loading = true;

    var params = $.extend({}, {page: 1}, this.lastParams);

    params.page++;

    this.trigger('query:append', params);
  };

  InfiniteScroll.prototype.showLoadingMore = function (_, data) {
    return data.pagination && data.pagination.more;
  };

  InfiniteScroll.prototype.createLoadingMore = function () {
    var $option = $(
      '<li class="option load-more" role="treeitem"></li>'
    );

    var message = this.options.get('translations').get('loadingMore');

    $option.html(message(this.lastParams));

    return $option;
  };

  return InfiniteScroll;
});

S2.define('select2/dropdown/attachBody',[
  'jquery',
  '../utils'
], function ($, Utils) {
  function AttachBody (decorated, $element, options) {
    this.$dropdownParent = options.get('dropdownParent') || document.body;

    decorated.call(this, $element, options);
  }

  AttachBody.prototype.bind = function (decorated, container, $container) {
    var self = this;

    var setupResultsEvents = false;

    decorated.call(this, container, $container);

    container.on('open', function () {
      self._showDropdown();
      self._attachPositioningHandler(container);

      if (!setupResultsEvents) {
        setupResultsEvents = true;

        container.on('results:all', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });

        container.on('results:append', function () {
          self._positionDropdown();
          self._resizeDropdown();
        });
      }
    });

    container.on('close', function () {
      self._hideDropdown();
      self._detachPositioningHandler(container);
    });

    this.$dropdownContainer.on('mousedown', function (evt) {
      evt.stopPropagation();
    });
  };

  AttachBody.prototype.destroy = function (decorated) {
    decorated.call(this);

    this.$dropdownContainer.remove();
  };

  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
    // Clone all of the container classes
    $dropdown.attr('class', $container.attr('class'));

    $dropdown.removeClass('select2');
    $dropdown.addClass('select2-container--open');

    $dropdown.css({
      position: 'absolute',
      top: -999999
    });

    this.$container = $container;
  };

  AttachBody.prototype.render = function (decorated) {
    var $container = $('<span></span>');

    var $dropdown = decorated.call(this);
    $container.append($dropdown);

    this.$dropdownContainer = $container;

    return $container;
  };

  AttachBody.prototype._hideDropdown = function (decorated) {
    this.$dropdownContainer.detach();
  };

  AttachBody.prototype._attachPositioningHandler = function (container) {
    var self = this;

    var scrollEvent = 'scroll.select2.' + container.id;
    var resizeEvent = 'resize.select2.' + container.id;
    var orientationEvent = 'orientationchange.select2.' + container.id;

    var $watchers = this.$container.parents().filter(Utils.hasScroll);
    $watchers.each(function () {
      $(this).data('select2-scroll-position', {
        x: $(this).scrollLeft(),
        y: $(this).scrollTop()
      });
    });

    $watchers.on(scrollEvent, function (ev) {
      var position = $(this).data('select2-scroll-position');
      $(this).scrollTop(position.y);
    });

    $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
      function (e) {
      self._positionDropdown();
      self._resizeDropdown();
    });
  };

  AttachBody.prototype._detachPositioningHandler = function (container) {
    var scrollEvent = 'scroll.select2.' + container.id;
    var resizeEvent = 'resize.select2.' + container.id;
    var orientationEvent = 'orientationchange.select2.' + container.id;

    var $watchers = this.$container.parents().filter(Utils.hasScroll);
    $watchers.off(scrollEvent);

    $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
  };

  AttachBody.prototype._positionDropdown = function () {
    var $window = $(window);

    var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
    var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');

    var newDirection = null;

    var position = this.$container.position();
    var offset = this.$container.offset();

    offset.bottom = offset.top + this.$container.outerHeight(false);

    var container = {
      height: this.$container.outerHeight(false)
    };

    container.top = offset.top;
    container.bottom = offset.top + container.height;

    var dropdown = {
      height: this.$dropdown.outerHeight(false)
    };

    var viewport = {
      top: $window.scrollTop(),
      bottom: $window.scrollTop() + $window.height()
    };

    var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
    var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);

    var css = {
      left: offset.left,
      top: container.bottom
    };

    if (!isCurrentlyAbove && !isCurrentlyBelow) {
      newDirection = 'below';
    }

    if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
      newDirection = 'above';
    } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
      newDirection = 'below';
    }

    if (newDirection == 'above' ||
      (isCurrentlyAbove && newDirection !== 'below')) {
      css.top = container.top - dropdown.height;
    }

    if (newDirection != null) {
      this.$dropdown
        .removeClass('select2-dropdown--below select2-dropdown--above')
        .addClass('select2-dropdown--' + newDirection);
      this.$container
        .removeClass('select2-container--below select2-container--above')
        .addClass('select2-container--' + newDirection);
    }

    this.$dropdownContainer.css(css);
  };

  AttachBody.prototype._resizeDropdown = function () {
    var css = {
      width: this.$container.outerWidth(false) + 'px'
    };

    if (this.options.get('dropdownAutoWidth')) {
      css.minWidth = css.width;
      css.width = 'auto';
    }

    this.$dropdown.css(css);
  };

  AttachBody.prototype._showDropdown = function (decorated) {
    this.$dropdownContainer.appendTo(this.$dropdownParent);

    this._positionDropdown();
    this._resizeDropdown();
  };

  return AttachBody;
});

S2.define('select2/dropdown/minimumResultsForSearch',[

], function () {
  function countResults (data) {
    var count = 0;

    for (var d = 0; d < data.length; d++) {
      var item = data[d];

      if (item.children) {
        count += countResults(item.children);
      } else {
        count++;
      }
    }

    return count;
  }

  function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
    this.minimumResultsForSearch = options.get('minimumResultsForSearch');

    if (this.minimumResultsForSearch < 0) {
      this.minimumResultsForSearch = Infinity;
    }

    decorated.call(this, $element, options, dataAdapter);
  }

  MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
    if (countResults(params.data.results) < this.minimumResultsForSearch) {
      return false;
    }

    return decorated.call(this, params);
  };

  return MinimumResultsForSearch;
});

S2.define('select2/dropdown/selectOnClose',[

], function () {
  function SelectOnClose () { }

  SelectOnClose.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('close', function () {
      self._handleSelectOnClose();
    });
  };

  SelectOnClose.prototype._handleSelectOnClose = function () {
    var $highlightedResults = this.getHighlightedResults();

    if ($highlightedResults.length < 1) {
      return;
    }

    this.trigger('select', {
        data: $highlightedResults.data('data')
    });
  };

  return SelectOnClose;
});

S2.define('select2/dropdown/closeOnSelect',[

], function () {
  function CloseOnSelect () { }

  CloseOnSelect.prototype.bind = function (decorated, container, $container) {
    var self = this;

    decorated.call(this, container, $container);

    container.on('select', function (evt) {
      self._selectTriggered(evt);
    });

    container.on('unselect', function (evt) {
      self._selectTriggered(evt);
    });
  };

  CloseOnSelect.prototype._selectTriggered = function (_, evt) {
    var originalEvent = evt.originalEvent;

    // Don't close if the control key is being held
    if (originalEvent && originalEvent.ctrlKey) {
      return;
    }

    this.trigger('close', {});
  };

  return CloseOnSelect;
});

S2.define('select2/i18n/en',[],function () {
  // English
  return {
    errorLoading: function () {
      return 'The results could not be loaded.';
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = 'Please delete ' + overChars + ' character';

      if (overChars != 1) {
        message += 's';
      }

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'Please enter ' + remainingChars + ' or more characters';

      return message;
    },
    loadingMore: function () {
      return 'Loading more results…';
    },
    maximumSelected: function (args) {
      var message = 'You can only select ' + args.maximum + ' item';

      if (args.maximum != 1) {
        message += 's';
      }

      return message;
    },
    noResults: function () {
      return 'No results found';
    },
    searching: function () {
      return 'Searching…';
    }
  };
});

S2.define('select2/defaults',[
  'jquery',
  'require',

  './results',

  './selection/single',
  './selection/multiple',
  './selection/placeholder',
  './selection/allowClear',
  './selection/search',
  './selection/eventRelay',

  './utils',
  './translation',
  './diacritics',

  './data/select',
  './data/array',
  './data/ajax',
  './data/tags',
  './data/tokenizer',
  './data/minimumInputLength',
  './data/maximumInputLength',
  './data/maximumSelectionLength',

  './dropdown',
  './dropdown/search',
  './dropdown/hidePlaceholder',
  './dropdown/infiniteScroll',
  './dropdown/attachBody',
  './dropdown/minimumResultsForSearch',
  './dropdown/selectOnClose',
  './dropdown/closeOnSelect',

  './i18n/en'
], function ($, require,

             ResultsList,

             SingleSelection, MultipleSelection, Placeholder, AllowClear,
             SelectionSearch, EventRelay,

             Utils, Translation, DIACRITICS,

             SelectData, ArrayData, AjaxData, Tags, Tokenizer,
             MinimumInputLength, MaximumInputLength, MaximumSelectionLength,

             Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
             AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,

             EnglishTranslation) {
  function Defaults () {
    this.reset();
  }

  Defaults.prototype.apply = function (options) {
    options = $.extend({}, this.defaults, options);

    if (options.dataAdapter == null) {
      if (options.ajax != null) {
        options.dataAdapter = AjaxData;
      } else if (options.data != null) {
        options.dataAdapter = ArrayData;
      } else {
        options.dataAdapter = SelectData;
      }

      if (options.minimumInputLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MinimumInputLength
        );
      }

      if (options.maximumInputLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MaximumInputLength
        );
      }

      if (options.maximumSelectionLength > 0) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          MaximumSelectionLength
        );
      }

      if (options.tags) {
        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
      }

      if (options.tokenSeparators != null || options.tokenizer != null) {
        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          Tokenizer
        );
      }

      if (options.query != null) {
        var Query = require(options.amdBase + 'compat/query');

        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          Query
        );
      }

      if (options.initSelection != null) {
        var InitSelection = require(options.amdBase + 'compat/initSelection');

        options.dataAdapter = Utils.Decorate(
          options.dataAdapter,
          InitSelection
        );
      }
    }

    if (options.resultsAdapter == null) {
      options.resultsAdapter = ResultsList;

      if (options.ajax != null) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          InfiniteScroll
        );
      }

      if (options.placeholder != null) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          HidePlaceholder
        );
      }

      if (options.selectOnClose) {
        options.resultsAdapter = Utils.Decorate(
          options.resultsAdapter,
          SelectOnClose
        );
      }
    }

    if (options.dropdownAdapter == null) {
      if (options.multiple) {
        options.dropdownAdapter = Dropdown;
      } else {
        var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);

        options.dropdownAdapter = SearchableDropdown;
      }

      if (options.minimumResultsForSearch !== 0) {
        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          MinimumResultsForSearch
        );
      }

      if (options.closeOnSelect) {
        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          CloseOnSelect
        );
      }

      if (
        options.dropdownCssClass != null ||
        options.dropdownCss != null ||
        options.adaptDropdownCssClass != null
      ) {
        var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');

        options.dropdownAdapter = Utils.Decorate(
          options.dropdownAdapter,
          DropdownCSS
        );
      }

      options.dropdownAdapter = Utils.Decorate(
        options.dropdownAdapter,
        AttachBody
      );
    }

    if (options.selectionAdapter == null) {
      if (options.multiple) {
        options.selectionAdapter = MultipleSelection;
      } else {
        options.selectionAdapter = SingleSelection;
      }

      // Add the placeholder mixin if a placeholder was specified
      if (options.placeholder != null) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          Placeholder
        );
      }

      if (options.allowClear) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          AllowClear
        );
      }

      if (options.multiple) {
        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          SelectionSearch
        );
      }

      if (
        options.containerCssClass != null ||
        options.containerCss != null ||
        options.adaptContainerCssClass != null
      ) {
        var ContainerCSS = require(options.amdBase + 'compat/containerCss');

        options.selectionAdapter = Utils.Decorate(
          options.selectionAdapter,
          ContainerCSS
        );
      }

      options.selectionAdapter = Utils.Decorate(
        options.selectionAdapter,
        EventRelay
      );
    }

    if (typeof options.language === 'string') {
      // Check if the language is specified with a region
      if (options.language.indexOf('-') > 0) {
        // Extract the region information if it is included
        var languageParts = options.language.split('-');
        var baseLanguage = languageParts[0];

        options.language = [options.language, baseLanguage];
      } else {
        options.language = [options.language];
      }
    }

    if ($.isArray(options.language)) {
      var languages = new Translation();
      options.language.push('en');

      var languageNames = options.language;

      for (var l = 0; l < languageNames.length; l++) {
        var name = languageNames[l];
        var language = {};

        try {
          // Try to load it with the original name
          language = Translation.loadPath(name);
        } catch (e) {
          try {
            // If we couldn't load it, check if it wasn't the full path
            name = this.defaults.amdLanguageBase + name;
            language = Translation.loadPath(name);
          } catch (ex) {
            // The translation could not be loaded at all. Sometimes this is
            // because of a configuration problem, other times this can be
            // because of how Select2 helps load all possible translation files.
            if (options.debug && window.console && console.warn) {
              console.warn(
                'Select2: The language file for "' + name + '" could not be ' +
                'automatically loaded. A fallback will be used instead.'
              );
            }

            continue;
          }
        }

        languages.extend(language);
      }

      options.translations = languages;
    } else {
      var baseTranslation = Translation.loadPath(
        this.defaults.amdLanguageBase + 'en'
      );
      var customTranslation = new Translation(options.language);

      customTranslation.extend(baseTranslation);

      options.translations = customTranslation;
    }

    return options;
  };

  Defaults.prototype.reset = function () {
    function stripDiacritics (text) {
      // Used 'uni range + named function' from http://jsperf.com/diacritics/18
      function match(a) {
        return DIACRITICS[a] || a;
      }

      return text.replace(/[^\u0000-\u007E]/g, match);
    }

    function matcher (params, data) {
      // Always return the object if there is nothing to compare
      if ($.trim(params.term) === '') {
        return data;
      }

      // Do a recursive check for options with children
      if (data.children && data.children.length > 0) {
        // Clone the data object if there are children
        // This is required as we modify the object to remove any non-matches
        var match = $.extend(true, {}, data);

        // Check each child of the option
        for (var c = data.children.length - 1; c >= 0; c--) {
          var child = data.children[c];

          var matches = matcher(params, child);

          // If there wasn't a match, remove the object in the array
          if (matches == null) {
            match.children.splice(c, 1);
          }
        }

        // If any children matched, return the new object
        if (match.children.length > 0) {
          return match;
        }

        // If there were no matching children, check just the plain object
        return matcher(params, match);
      }

      var original = stripDiacritics(data.text).toUpperCase();
      var term = stripDiacritics(params.term).toUpperCase();

      // Check if the text contains the term
      if (original.indexOf(term) > -1) {
        return data;
      }

      // If it doesn't contain the term, don't return anything
      return null;
    }

    this.defaults = {
      amdBase: './',
      amdLanguageBase: './i18n/',
      closeOnSelect: true,
      debug: false,
      dropdownAutoWidth: false,
      escapeMarkup: Utils.escapeMarkup,
      language: EnglishTranslation,
      matcher: matcher,
      minimumInputLength: 0,
      maximumInputLength: 0,
      maximumSelectionLength: 0,
      minimumResultsForSearch: 0,
      selectOnClose: false,
      sorter: function (data) {
        return data;
      },
      templateResult: function (result) {
        return result.text;
      },
      templateSelection: function (selection) {
        return selection.text;
      },
      theme: 'default',
      width: 'resolve'
    };
  };

  Defaults.prototype.set = function (key, value) {
    var camelKey = $.camelCase(key);

    var data = {};
    data[camelKey] = value;

    var convertedData = Utils._convertData(data);

    $.extend(this.defaults, convertedData);
  };

  var defaults = new Defaults();

  return defaults;
});

S2.define('select2/options',[
  'require',
  'jquery',
  './defaults',
  './utils'
], function (require, $, Defaults, Utils) {
  function Options (options, $element) {
    this.options = options;

    if ($element != null) {
      this.fromElement($element);
    }

    this.options = Defaults.apply(this.options);

    if ($element && $element.is('input')) {
      var InputCompat = require(this.get('amdBase') + 'compat/inputData');

      this.options.dataAdapter = Utils.Decorate(
        this.options.dataAdapter,
        InputCompat
      );
    }
  }

  Options.prototype.fromElement = function ($e) {
    var excludedData = ['select2'];

    if (this.options.multiple == null) {
      this.options.multiple = $e.prop('multiple');
    }

    if (this.options.disabled == null) {
      this.options.disabled = $e.prop('disabled');
    }

    if (this.options.language == null) {
      if ($e.prop('lang')) {
        this.options.language = $e.prop('lang').toLowerCase();
      } else if ($e.closest('[lang]').prop('lang')) {
        this.options.language = $e.closest('[lang]').prop('lang');
      }
    }

    if (this.options.dir == null) {
      if ($e.prop('dir')) {
        this.options.dir = $e.prop('dir');
      } else if ($e.closest('[dir]').prop('dir')) {
        this.options.dir = $e.closest('[dir]').prop('dir');
      } else {
        this.options.dir = 'ltr';
      }
    }

    $e.prop('disabled', this.options.disabled);
    $e.prop('multiple', this.options.multiple);

    if ($e.data('select2Tags')) {
      if (this.options.debug && window.console && console.warn) {
        console.warn(
          'Select2: The `data-select2-tags` attribute has been changed to ' +
          'use the `data-data` and `data-tags="true"` attributes and will be ' +
          'removed in future versions of Select2.'
        );
      }

      $e.data('data', $e.data('select2Tags'));
      $e.data('tags', true);
    }

    if ($e.data('ajaxUrl')) {
      if (this.options.debug && window.console && console.warn) {
        console.warn(
          'Select2: The `data-ajax-url` attribute has been changed to ' +
          '`data-ajax--url` and support for the old attribute will be removed' +
          ' in future versions of Select2.'
        );
      }

      $e.attr('ajax--url', $e.data('ajaxUrl'));
      $e.data('ajax--url', $e.data('ajaxUrl'));
    }

    var dataset = {};

    // Prefer the element's `dataset` attribute if it exists
    // jQuery 1.x does not correctly handle data attributes with multiple dashes
    if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
      dataset = $.extend(true, {}, $e[0].dataset, $e.data());
    } else {
      dataset = $e.data();
    }

    var data = $.extend(true, {}, dataset);

    data = Utils._convertData(data);

    for (var key in data) {
      if ($.inArray(key, excludedData) > -1) {
        continue;
      }

      if ($.isPlainObject(this.options[key])) {
        $.extend(this.options[key], data[key]);
      } else {
        this.options[key] = data[key];
      }
    }

    return this;
  };

  Options.prototype.get = function (key) {
    return this.options[key];
  };

  Options.prototype.set = function (key, val) {
    this.options[key] = val;
  };

  return Options;
});

S2.define('select2/core',[
  'jquery',
  './options',
  './utils',
  './keys'
], function ($, Options, Utils, KEYS) {
  var Select2 = function ($element, options) {
    if ($element.data('select2') != null) {
      $element.data('select2').destroy();
    }

    this.$element = $element;

    this.id = this._generateId($element);

    options = options || {};

    this.options = new Options(options, $element);

    Select2.__super__.constructor.call(this);

    // Set up the tabindex

    var tabindex = $element.attr('tabindex') || 0;
    $element.data('old-tabindex', tabindex);
    $element.attr('tabindex', '-1');

    // Set up containers and adapters

    var DataAdapter = this.options.get('dataAdapter');
    this.dataAdapter = new DataAdapter($element, this.options);

    var $container = this.render();

    this._placeContainer($container);

    var SelectionAdapter = this.options.get('selectionAdapter');
    this.selection = new SelectionAdapter($element, this.options);
    this.$selection = this.selection.render();

    this.selection.position(this.$selection, $container);

    var DropdownAdapter = this.options.get('dropdownAdapter');
    this.dropdown = new DropdownAdapter($element, this.options);
    this.$dropdown = this.dropdown.render();

    this.dropdown.position(this.$dropdown, $container);

    var ResultsAdapter = this.options.get('resultsAdapter');
    this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
    this.$results = this.results.render();

    this.results.position(this.$results, this.$dropdown);

    // Bind events

    var self = this;

    // Bind the container to all of the adapters
    this._bindAdapters();

    // Register any DOM event handlers
    this._registerDomEvents();

    // Register any internal event handlers
    this._registerDataEvents();
    this._registerSelectionEvents();
    this._registerDropdownEvents();
    this._registerResultsEvents();
    this._registerEvents();

    // Set the initial state
    this.dataAdapter.current(function (initialData) {
      self.trigger('selection:update', {
        data: initialData
      });
    });

    // Hide the original select
    $element.addClass('select2-hidden-accessible');
    $element.attr('aria-hidden', 'true');

    // Synchronize any monitored attributes
    this._syncAttributes();

    $element.data('select2', this);
  };

  Utils.Extend(Select2, Utils.Observable);

  Select2.prototype._generateId = function ($element) {
    var id = '';

    if ($element.attr('id') != null) {
      id = $element.attr('id');
    } else if ($element.attr('name') != null) {
      id = $element.attr('name') + '-' + Utils.generateChars(2);
    } else {
      id = Utils.generateChars(4);
    }

    id = 'select2-' + id;

    return id;
  };

  Select2.prototype._placeContainer = function ($container) {
    $container.insertAfter(this.$element);

    var width = this._resolveWidth(this.$element, this.options.get('width'));

    if (width != null) {
      $container.css('width', width);
    }
  };

  Select2.prototype._resolveWidth = function ($element, method) {
    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;

    if (method == 'resolve') {
      var styleWidth = this._resolveWidth($element, 'style');

      if (styleWidth != null) {
        return styleWidth;
      }

      return this._resolveWidth($element, 'element');
    }

    if (method == 'element') {
      var elementWidth = $element.outerWidth(false);

      if (elementWidth <= 0) {
        return 'auto';
      }

      return elementWidth + 'px';
    }

    if (method == 'style') {
      var style = $element.attr('style');

      if (typeof(style) !== 'string') {
        return null;
      }

      var attrs = style.split(';');

      for (var i = 0, l = attrs.length; i < l; i = i + 1) {
        var attr = attrs[i].replace(/\s/g, '');
        var matches = attr.match(WIDTH);

        if (matches !== null && matches.length >= 1) {
          return matches[1];
        }
      }

      return null;
    }

    return method;
  };

  Select2.prototype._bindAdapters = function () {
    this.dataAdapter.bind(this, this.$container);
    this.selection.bind(this, this.$container);

    this.dropdown.bind(this, this.$container);
    this.results.bind(this, this.$container);
  };

  Select2.prototype._registerDomEvents = function () {
    var self = this;

    this.$element.on('change.select2', function () {
      self.dataAdapter.current(function (data) {
        self.trigger('selection:update', {
          data: data
        });
      });
    });

    this._sync = Utils.bind(this._syncAttributes, this);

    if (this.$element[0].attachEvent) {
      this.$element[0].attachEvent('onpropertychange', this._sync);
    }

    var observer = window.MutationObserver ||
      window.WebKitMutationObserver ||
      window.MozMutationObserver
    ;

    if (observer != null) {
      this._observer = new observer(function (mutations) {
        $.each(mutations, self._sync);
      });
      this._observer.observe(this.$element[0], {
        attributes: true,
        subtree: false
      });
    } else if (this.$element[0].addEventListener) {
      this.$element[0].addEventListener('DOMAttrModified', self._sync, false);
    }
  };

  Select2.prototype._registerDataEvents = function () {
    var self = this;

    this.dataAdapter.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerSelectionEvents = function () {
    var self = this;
    var nonRelayEvents = ['toggle', 'focus'];

    this.selection.on('toggle', function () {
      self.toggleDropdown();
    });

    this.selection.on('focus', function (params) {
      self.focus(params);
    });

    this.selection.on('*', function (name, params) {
      if ($.inArray(name, nonRelayEvents) !== -1) {
        return;
      }

      self.trigger(name, params);
    });
  };

  Select2.prototype._registerDropdownEvents = function () {
    var self = this;

    this.dropdown.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerResultsEvents = function () {
    var self = this;

    this.results.on('*', function (name, params) {
      self.trigger(name, params);
    });
  };

  Select2.prototype._registerEvents = function () {
    var self = this;

    this.on('open', function () {
      self.$container.addClass('select2-container--open');
    });

    this.on('close', function () {
      self.$container.removeClass('select2-container--open');
    });

    this.on('enable', function () {
      self.$container.removeClass('select2-container--disabled');
    });

    this.on('disable', function () {
      self.$container.addClass('select2-container--disabled');
    });

    this.on('blur', function () {
      self.$container.removeClass('select2-container--focus');
    });

    this.on('query', function (params) {
      if (!self.isOpen()) {
        self.trigger('open', {});
      }

      this.dataAdapter.query(params, function (data) {
        self.trigger('results:all', {
          data: data,
          query: params
        });
      });
    });

    this.on('query:append', function (params) {
      this.dataAdapter.query(params, function (data) {
        self.trigger('results:append', {
          data: data,
          query: params
        });
      });
    });

    this.on('keypress', function (evt) {
      var key = evt.which;

      if (self.isOpen()) {
        if (key === KEYS.ESC || key === KEYS.TAB ||
            (key === KEYS.UP && evt.altKey)) {
          self.close();

          evt.preventDefault();
        } else if (key === KEYS.ENTER) {
          self.trigger('results:select', {});

          evt.preventDefault();
        } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
          self.trigger('results:toggle', {});

          evt.preventDefault();
        } else if (key === KEYS.UP) {
          self.trigger('results:previous', {});

          evt.preventDefault();
        } else if (key === KEYS.DOWN) {
          self.trigger('results:next', {});

          evt.preventDefault();
        }
      } else {
        if (key === KEYS.ENTER || key === KEYS.SPACE ||
            (key === KEYS.DOWN && evt.altKey)) {
          self.open();

          evt.preventDefault();
        }
      }
    });
  };

  Select2.prototype._syncAttributes = function () {
    this.options.set('disabled', this.$element.prop('disabled'));

    if (this.options.get('disabled')) {
      if (this.isOpen()) {
        this.close();
      }

      this.trigger('disable', {});
    } else {
      this.trigger('enable', {});
    }
  };

  /**
   * Override the trigger method to automatically trigger pre-events when
   * there are events that can be prevented.
   */
  Select2.prototype.trigger = function (name, args) {
    var actualTrigger = Select2.__super__.trigger;
    var preTriggerMap = {
      'open': 'opening',
      'close': 'closing',
      'select': 'selecting',
      'unselect': 'unselecting'
    };

    if (name in preTriggerMap) {
      var preTriggerName = preTriggerMap[name];
      var preTriggerArgs = {
        prevented: false,
        name: name,
        args: args
      };

      actualTrigger.call(this, preTriggerName, preTriggerArgs);

      if (preTriggerArgs.prevented) {
        args.prevented = true;

        return;
      }
    }

    actualTrigger.call(this, name, args);
  };

  Select2.prototype.toggleDropdown = function () {
    if (this.options.get('disabled')) {
      return;
    }

    if (this.isOpen()) {
      this.close();
    } else {
      this.open();
    }
  };

  Select2.prototype.open = function () {
    if (this.isOpen()) {
      return;
    }

    this.trigger('query', {});
  };

  Select2.prototype.close = function () {
    if (!this.isOpen()) {
      return;
    }

    this.trigger('close', {});
  };

  Select2.prototype.isOpen = function () {
    return this.$container.hasClass('select2-container--open');
  };

  Select2.prototype.hasFocus = function () {
    return this.$container.hasClass('select2-container--focus');
  };

  Select2.prototype.focus = function (data) {
    // No need to re-trigger focus events if we are already focused
    if (this.hasFocus()) {
      return;
    }

    this.$container.addClass('select2-container--focus');
    this.trigger('focus', {});
  };

  Select2.prototype.enable = function (args) {
    if (this.options.get('debug') && window.console && console.warn) {
      console.warn(
        'Select2: The `select2("enable")` method has been deprecated and will' +
        ' be removed in later Select2 versions. Use $element.prop("disabled")' +
        ' instead.'
      );
    }

    if (args == null || args.length === 0) {
      args = [true];
    }

    var disabled = !args[0];

    this.$element.prop('disabled', disabled);
  };

  Select2.prototype.data = function () {
    if (this.options.get('debug') &&
        arguments.length > 0 && window.console && console.warn) {
      console.warn(
        'Select2: Data can no longer be set using `select2("data")`. You ' +
        'should consider setting the value instead using `$element.val()`.'
      );
    }

    var data = [];

    this.dataAdapter.current(function (currentData) {
      data = currentData;
    });

    return data;
  };

  Select2.prototype.val = function (args) {
    if (this.options.get('debug') && window.console && console.warn) {
      console.warn(
        'Select2: The `select2("val")` method has been deprecated and will be' +
        ' removed in later Select2 versions. Use $element.val() instead.'
      );
    }

    if (args == null || args.length === 0) {
      return this.$element.val();
    }

    var newVal = args[0];

    if ($.isArray(newVal)) {
      newVal = $.map(newVal, function (obj) {
        return obj.toString();
      });
    }

    this.$element.val(newVal).trigger('change');
  };

  Select2.prototype.destroy = function () {
    this.$container.remove();

    if (this.$element[0].detachEvent) {
      this.$element[0].detachEvent('onpropertychange', this._sync);
    }

    if (this._observer != null) {
      this._observer.disconnect();
      this._observer = null;
    } else if (this.$element[0].removeEventListener) {
      this.$element[0]
        .removeEventListener('DOMAttrModified', this._sync, false);
    }

    this._sync = null;

    this.$element.off('.select2');
    this.$element.attr('tabindex', this.$element.data('old-tabindex'));

    this.$element.removeClass('select2-hidden-accessible');
    this.$element.attr('aria-hidden', 'false');
    this.$element.removeData('select2');

    this.dataAdapter.destroy();
    this.selection.destroy();
    this.dropdown.destroy();
    this.results.destroy();

    this.dataAdapter = null;
    this.selection = null;
    this.dropdown = null;
    this.results = null;
  };

  Select2.prototype.render = function () {
    var $container = $(
      '<span class="select2 select2-container">' +
        '<span class="selection"></span>' +
        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
      '</span>'
    );

    $container.attr('dir', this.options.get('dir'));

    this.$container = $container;

    this.$container.addClass('select2-container--' + this.options.get('theme'));

    $container.data('element', this.$element);

    return $container;
  };

  return Select2;
});

S2.define('jquery.select2',[
  'jquery',
  'require',

  './select2/core',
  './select2/defaults'
], function ($, require, Select2, Defaults) {
  // Force jQuery.mousewheel to be loaded if it hasn't already
    require('jquery-mousewheel');

  if ($.fn.select2 == null) {
    // All methods that should return the element
    var thisMethods = ['open', 'close', 'destroy'];

    $.fn.select2 = function (options) {
      options = options || {};

      if (typeof options === 'object') {
        this.each(function () {
          var instanceOptions = $.extend({}, options, true);

          var instance = new Select2($(this), instanceOptions);
        });

        return this;
      } else if (typeof options === 'string') {
        var instance = this.data('select2');

        if (instance == null && window.console && console.error) {
          console.error(
            'The select2(\'' + options + '\') method was called on an ' +
            'element that is not using Select2.'
          );
        }

        var args = Array.prototype.slice.call(arguments, 1);

        var ret = instance[options](args);

        // Check if we should be returning `this`
        if ($.inArray(options, thisMethods) > -1) {
          return this;
        }

        return ret;
      } else {
        throw new Error('Invalid arguments for Select2: ' + options);
      }
    };
  }

  if ($.fn.select2.defaults == null) {
    $.fn.select2.defaults = Defaults;
  }

  return Select2;
});

S2.define('jquery-mousewheel',[
  'jquery'
], function ($) {
  // Used to shim jQuery.mousewheel for non-full builds.
  return $;
});

  // Return the AMD loader configuration so it can be used outside of this file
  return {
    define: S2.define,
    require: S2.require
  };
}());

  // Autoload the jQuery bindings
  // We know that all of the modules exist above this, so we're safe
  var select2 = S2.require('jquery.select2');

  // Hold the AMD module references on the jQuery function that was just loaded
  // This allows Select2 to use the internal loader outside of this file, such
  // as in the language files.
  jQuery.fn.select2.amd = S2;

  // Return the Select2 instance for anyone who is importing it.
  return select2;
}));

},{"jquery":214,"jquery-mousewheel":213}],181:[function(require,module,exports){
/*!
 * jquery.sumoselect - v2.1.0
 * http://hemantnegi.github.io/jquery.sumoselect
 * 2014-04-08
 *
 * Copyright 2015 Hemant Negi
 * Email : hemant.frnz@gmail.com
 * Compressor http://refresh-sf.com/
 */

(function (factory) {
    if (typeof define === "function" && define.amd) {
        // AMD. Register as anonymous module.
        define(["jquery", "lodash"], factory);
    } else if (typeof exports === "object") {
        // Node / CommonJS
        factory(require("jquery", "lodash"));
    } else {
        // Browser globals.
        factory(jQuery, _);
    }
})(function ($, _) {

    "namespace sumo";
    $.fn.sumoSelect = function (options) {

        // var is_visible_default = false;
        //$(document).click(function () { is_visible_default = false; });

        // This is the easiest way to have default options.
        var settings = $.extend({
            placeholder: "Ничего не выбрано",   // Dont change it here.
            csvDispCount: 1,              // display no. of items in multiselect. 0 to display all.
            captionFormat:"Выбрано {0} из {1}", // format of caption text. you can set your locale.
            floatWidth: 400,              // Screen width of device at which the list is rendered in floating popup fashion.
            forceCustomRendering: false,  // force the custom modal on all devices below floatWidth resolution.
            nativeOnDevice: ["Android", "BlackBerry", "iPhone", "iPad", "iPod", "Opera Mini", "IEMobile", "Silk"], //
            outputAsCSV: false,           // true to POST data as csv ( false for Html control array ie. deafault select )
            csvSepChar: ",",              // seperation char in csv mode
            okCancelInMulti: false,       //display ok cancel buttons in desktop mode multiselect also.
            triggerChangeCombined: true,  // im multi select mode wether to trigger change event on individual selection or combined selection.
            selectAll: false,             // to display select all button in multiselect mode.|| also select all will not be available on mobile devices.
            selectAlltext: "Выбрать все"   // the text to display for select all.

        }, options);

        var ret = this.each(function () {
            var selObj = this; // the original select object.
            if (this.sumo || !$(this).is("select")) return; //already initialized

            this.sumo = {
                E: $(selObj),   //the jquery object of original select element.
                is_multi: $(selObj).attr("multiple"),  //if its a mmultiple select
                select: "",
                caption: "",
                placeholder: "",
                optDiv: "",
                captionContainer: "",
                is_floating: false,
                is_opened: false,
                //backdrop: '',
                mob:false, // if to open device default select
                Pstate: [],
                selectedCount: 0,

                createElems: function () {
                    var O = this;
                    O.E.wrap("<div class=\"sumo-select\" tabindex=\"0\">");
                    O.select = O.E.parent();
                    O.caption = $("<span></span>");
                    O.captionContainer = $("<div class=\"caption-container\"><label><i></i></label></div>").addClass("select-box").attr("style", O.E.attr("style")).prepend(O.caption);
                    O.select.append(O.captionContainer);

                    if(O.E.attr("disabled"))
                        O.select.addClass("disabled").removeAttr("tabindex");

                    //if output as csv and is a multiselect.
                    if (settings.outputAsCSV && O.is_multi && O.E.attr("name")) {
                        //create a hidden field to store csv value.
                        O.select.append($("<input class=\"hidden-input\" type=\"hidden\" />").attr("name", O.E.attr("name")).val(O.getSelStr()));

                        // so it can not post the original select.
                        O.E.removeAttr("name");
                    }

                    //break for mobile rendring.. if forceCustomRendering is false
                    if (O.isMobile() && !settings.forceCustomRendering) {
                        O.setNativeMobile();
                        return;
                    }

                    //hide original select
                    O.E.hide();

                    //## Creating the list...
                    O.optDiv = $("<div class=\"options-wrapper\">");

                    //branch for floating list in low res devices.
                    O.floatingList();

                    //Creating the markup for the available options
                    ul = $("<ul class=\"options\">");
                    O.optDiv.append(ul);

                    // Select all functionality
                    if (settings.selectAll) O.selAll();
                    if (settings.clearAll && O.is_multi) O.clearAll();

                    $(O.E.children("option")).each(function (i, opt) {       // parsing options to li
                        opt = $(opt);
                        O.createLi(opt);
                    });

                    //if multiple then add the class multiple and add OK / CANCEL button
                    if (O.is_multi) O.multiSelelect();

                    O.select.append(O.optDiv);
                    O._handleMax();
                    O.basicEvents();
                    O.selAllState();
                },

                //## Creates a LI element from a given option and binds events to it
                //## Adds it to UL at a given index (Last by default)
                createLi: function (opt,i) {
                    var O = this;

                    var value = opt.val();
                    if (!value || value.length === 0) {
                        return;
                    }

                    if (!opt.attr("value")) {
                        opt.attr("value", value);
                    }

                    li = $("<li data-val=\"" + opt.val() + "\"><label>" + opt.text() + "</label></li>");
                    if (O.is_multi) li.prepend("<span><i></i></span>");

                    if (opt[0].disabled)
                        li = li.addClass("disabled");

                    O.onOptClick(li);

                    if (opt[0].selected) {
                        li.addClass("selected");
                        O.selectedCount++;
                    }

                    if (opt.attr("class"))
                        li.addClass(opt.attr("class"));

                    ul = O.optDiv.children("ul.options");
                    if (typeof i == "undefined")
                        ul.append(li);
                    else
                        ul.children("li").eq(i).before(li);

                    return li;
                },

                //## Returns the selected items as string in a Multiselect.
                getSelStr: function () {
                    // get the pre selected items.
                    sopt = [];
                    this.E.children("option:selected").each(function () { sopt.push($(this).val()); });
                    return sopt.join(settings.csvSepChar);
                },

                //## THOSE OK/CANCEL BUTTONS ON MULTIPLE SELECT.
                multiSelelect: function () {
                    var O = this;
                    O.optDiv.addClass("multiple");
                    O.okbtn = $("<p class=\"btnOk\">OK</p>").click(function () {

                        //if combined change event is set.
                        if (settings.triggerChangeCombined) {

                            //check for a change in the selection.
                            changed = false;
                            if (O.E.children("option:selected").length != O.Pstate.length) {
                                changed = true;
                            }
                            else {
                                O.E.children("option:selected").each(function () {
                                    if (O.Pstate.indexOf($(this).val()) < 0) changed = true;
                                });
                            }

                            if (changed) {
                                O.E.trigger("change").trigger("click");
                                O.setText();
                            }
                        }
                        O.hideOpts();
                    });
                    O.cancelBtn = $("<p class=\"btnCancel\">Отмена</p>").click(function () {
                        O._cnbtn();
                        O.hideOpts();
                    });
                    O.optDiv.append($("<div class=\"multicontrols\">").append(O.okbtn).append(O.cancelBtn));
                },

                _cnbtn: function () {
                    var O = this;
                    //remove all selections
                    O.E.children("option:selected").each(function () { this.selected = false; });
                    O.optDiv.find("li.selected").removeClass("selected")
                    this.selectedCount = 0;

                    //restore selections from saved state.
                    for (i = 0; i < O.Pstate.length; i++) {
                        O.E.children("option[value=\"" + O.Pstate[i] + "\"]")[0].selected = true;
                        O.optDiv.find("li[data-val=\"" + O.Pstate[i] + "\"]").addClass("selected");
                        this.selectedCount++;
                    }
                    O._handleMax();
                    O.selAllState();
                },

                _handleMax() {
                    // Disable options if max reached
                    if (settings.max) {
                        if (this.selectedCount >= +settings.max) {
                            this.optDiv.find('li').not('.hidden').each((ix, e) => {
                                if (!$(e).hasClass('selected')) {
                                    $(e).addClass('temporary-disabled disabled');
                                }
                            });
                        } else {
                            // Enable options back
                            this.optDiv.find('li').not('.hidden').each((ix, e) => {
                                if ($(e).hasClass('temporary-disabled')) {
                                    $(e).removeClass('temporary-disabled disabled');
                                }
                            });
                        }
                    }
                },

                clearAll() {
                    const O = this;
                    if (!O.is_multi) return;
                    O.selAll = $('<p class="reset-all"><label></label></p>');
                    O.selAll.find('label')[0].innerText = settings.clearAlltext;
                    O.selAll.on('click', () => {
                        O.selAll.removeClass('selected');
                        O.toggSelAll(false, 1);
                        O.selectedCount = 0;
                        if (settings.max) {
                            O._handleMax();
                        }
                        if (settings.closeAfterClearAll) {
                            O.hideOpts();
                        }
                    });

                    O.optDiv.prepend(O.selAll);
                },

                selAll:function(){
                    var O = this;
                    if(!O.is_multi)return;
                    O.chkAll = $("<i>");
                    O.selAll = $("<p class=\"select-all\"><label>" + settings.selectAlltext + "</label></p>").prepend($("<span></span>").append(O.chkAll));
                    O.selAll.on("click", function () {
                        //O.toggSelAll(!);
                        O.selAll.toggleClass("selected");
                        O.optDiv.find("ul.options li").each(function(ix,e){
                            e = $(e);
                            if(O.selAll.hasClass("selected")){
                                if(!e.hasClass("selected"))e.trigger("click");
                            }
                            else
                                if(e.hasClass("selected"))e.trigger("click");
                        });
                    });

                    O.optDiv.prepend(O.selAll);
                },

                selAllState: function () {
                    var O = this;
                    if (settings.selectAll) {
                        var sc = 0, vc = 0;
                        O.optDiv.find("ul.options li").each(function (ix, e) {
                            if ($(e).hasClass("selected")) sc++;
                            if (!$(e).hasClass("disabled")) vc++;
                        });
                        //select all checkbox state change.
                        if (sc == vc) O.selAll.removeClass("partial").addClass("selected");
                        else if (sc == 0) O.selAll.removeClass("selected partial");
                        else O.selAll.addClass("partial")//.removeClass('selected');
                    }
                },

                showOpts: function () {
                    var O = this;
                    if (O.E.attr("disabled")) return; // if select is disabled then retrun
                    O.is_opened = true;
                    //O.backdrop.show();
                    O.optDiv.addClass("open");

                    // hide options on click outside.
                    $(document).on("click.sumo", function (e) {
                            if (!O.select.is(e.target)                  // if the target of the click isn't the container...
                                && O.select.has(e.target).length === 0){ // ... nor a descendant of the container
//                               if (O.is_multi && settings.okCancelInMulti)
//                                    O._cnbtn();
//                                O.hideOpts();
								if(!O.is_opened)return;
								O.hideOpts();
								if (O.is_multi && settings.okCancelInMulti)O._cnbtn();
                            }
                    });

                    if (O.is_floating) {
                        H = O.optDiv.children("ul").outerHeight() + 2;  // +2 is clear fix
                        if (O.is_multi) H = H + parseInt(O.optDiv.css("padding-bottom"));
                        O.optDiv.css("height", H);
                    }

                    //maintain state when ok/cancel buttons are available.
                    if (O.is_multi && (O.is_floating || settings.okCancelInMulti)) {
                        O.Pstate = [];
                        O.E.children("option:selected").each(function () { O.Pstate.push($(this).val()); });
                    }
                },
                hideOpts: function () {
                    var O = this;
                    O.is_opened = false;
                    O.optDiv.removeClass("open").find("ul li.selected").removeClass("sel");
                    $(document).off("click.sumo");
                },
                setOnOpen: function () {
                    var O = this;
                    var li = O.optDiv.find("ul li").eq(O.E[0].selectedIndex);
                    li.addClass("sel");
                    O.showOpts();
                },
                nav: function (up) {
                    var O = this, c;
                    var sel = O.optDiv.find("ul li.selected");
                    if (O.is_opened && sel.length) {
                        if (up)
                            c = sel.prevAll("li:not(.disabled)");
                        else
                            c = sel.nextAll("li:not(.disabled)");
                        if (!c.length)return;
                        sel.removeClass("sel");
                        sel = c.first().addClass("sel");

                        // setting sel item to visible view.
                        var ul = O.optDiv.find("ul"),
                            st = ul.scrollTop(),
                            t = sel.position().top + st;                            
                        if(t >= st + ul.height()-sel.outerHeight())
                            ul.scrollTop(t - ul.height() + sel.outerHeight());
                        if(t<st)
                            ul.scrollTop(t);

                    }
                    else
                        O.setOnOpen();
                },

                basicEvents: function () {
                    var O = this;
                    O.captionContainer.click(function (evt) {
                        O.E.trigger("click");
                        if (O.is_opened) O.hideOpts(); else O.showOpts();
                        evt.stopPropagation();
                    });

                  /*  O.select.on('blur focusout', function () {
                        if(!O.is_opened)return;
                        //O.hideOpts();
                        O.hideOpts();

                    if (O.is_multi && settings.okCancelInMulti)
                         O._cnbtn();
                    })*/
                        O.select.on("keydown", function (e) {
                            switch (e.which) {
                                case 38: // up
                                    O.nav(true);
                                    break;

                                case 40: // down
                                    O.nav(false);
                                    break;

                                case 32: // space
                                case 13: // enter
                                    if (O.is_opened)
                                        O.optDiv.find("ul li.selected").trigger("click");
                                    else
                                        O.setOnOpen();
                                    break;
								case 9:	 //tab
                                case 27: // esc
                                     if (O.is_multi && settings.okCancelInMulti)O._cnbtn();
                                    O.hideOpts();
                                    return;

                                default:
                                    return; // exit this handler for other keys
                            }
                            e.preventDefault(); // prevent the default action (scroll / move caret)
                        });

                    $(window).on("resize.sumo", function () {
                        O.floatingList();
                    });
                },

                onOptClick: function (li) {
                    var O = this;
                    li.click(function () {
                        var li = $(this);
                        if(li.hasClass("disabled"))return;
                        var txt = "";
                        if (O.is_multi) {
                            li.toggleClass("selected");
                            O.E.children("option[value=\"" + li.data("val") + "\"]")[0].selected = li.hasClass("selected");
                            if (li.hasClass("selected") === false) {
                                O.selectedCount--;
                            } else {
                                O.selectedCount++;
                            }
                            if (settings.max) {
                                O._handleMax();
                            }

                            O.selAllState();
                        }
                        else {
                            li.parent().find("li.selected").removeClass("selected"); //if not multiselect then remove all selections from this list
                            li.toggleClass("selected");
                            O.E.val(li.attr("data-val"));   //set the value of select element
                            O.selectedCount = 1;
                        }

                        //branch for combined change event.
                        if (!(O.is_multi && settings.triggerChangeCombined && (O.is_floating || settings.okCancelInMulti))) {
                            O.setText();
                            O.E.trigger("change").trigger("click");
                        }

                        if (!O.is_multi) O.hideOpts(); //if its not a multiselect then hide on single select.
                    });
                },

                setText: function () {
                    var O = this;
                    O.placeholder = "";
                    if (O.is_multi) {
                        var totalItems = O.E.children().not(":disabled");
                        var sels = totalItems.filter(":selected"); //selected options.

                        for (i = 0; i < sels.length; i++) {
                            if (i >= settings.csvDispCount && settings.csvDispCount) {
                                O.placeholder = settings.captionFormat.replace("{0}", sels.length).replace("{1}", totalItems.length);
                                //O.placeholder = i + '+ Selected';
                                break;
                            }
                            else O.placeholder += $(sels[i]).text() + ", ";
                        }
                        O.placeholder = O.placeholder.replace(/,([^,]*)$/, "$1"); //remove unexpected "," from last.
                    }
                    else {
                        O.placeholder = O.E.children(":selected").not(":disabled").text();
                    }

                    var is_placeholder = false;

                    if (!O.placeholder) {

                        is_placeholder = true;

                        O.placeholder = O.E.attr("placeholder");
                        if (!O.placeholder)                  //if placeholder is there then set it
                        {
                            O.placeholder = O.E.children("option:disabled:selected").text();
                            //if (!O.placeholder && settings.placeholder === 'Select Here')
                            //    O.placeholder = O.E.val();
                        }
                    }

                    O.placeholder = O.placeholder ? O.placeholder : settings.placeholder

                    //set display text
                    O.caption.html(O.placeholder);

                    //set the hidden field if post as csv is true.
                    var csvField = O.select.find("input.hidden-input");
                    if (csvField.length) csvField.val(O.getSelStr());

                    //add class placeholder if its a placeholder text.
                    if (is_placeholder) O.caption.addClass("placeholder"); else O.caption.removeClass("placeholder");
                    return O.placeholder;
                },

                isMobile: function () {

                    // Adapted from http://www.detectmobilebrowsers.com
                    var ua = navigator.userAgent || navigator.vendor || window.opera;

                    // Checks for iOs, Android, Blackberry, Opera Mini, and Windows mobile devices
                    for (var i = 0; i < settings.nativeOnDevice.length; i++) if (ua.toString().toLowerCase().indexOf(settings.nativeOnDevice[i].toLowerCase()) > 0) return settings.nativeOnDevice[i];
                    return false;
                },

                setNativeMobile: function () {
                    var O = this;
                    O.E.addClass("hidden-select");
					O.mob = true;
                    O.E.change(function () {
                        O.setText();
                    });
                },

                floatingList: function () {
                    var O = this;
                    //called on init and also on resize.
                    //O.is_floating = true if window width is < specified float width
                    O.is_floating = $(window).width() <= settings.floatWidth;

                    //set class isFloating
                    O.optDiv.toggleClass("isFloating", O.is_floating);

                    //remove height if not floating
                    if (!O.is_floating) O.optDiv.css("height", "");

                    //toggle class according to okCancelInMulti flag only when it is not floating
                    O.optDiv.toggleClass("okCancelInMulti", settings.okCancelInMulti && !O.is_floating);
                },

                //HELPERS FOR OUTSIDERS
                // validates range of given item operations
                vRange: function (i) {
                    var O = this;
                    opts = O.E.children("option");
                    if (opts.length <= i || i < 0) throw "index out of bounds"
                    return O;
                },

                //toggles selection on c as boolean.
                toggSel: function (c, i) {
                    var O = this.vRange(i);
                    if (O.E.children("option")[i].disabled) return;
                    O.E.children("option")[i].selected = c;
                    if(!O.mob)O.optDiv.find("ul.options li").eq(i).toggleClass("selected",c);
                    O.setText();
                },

                //toggles disabled on c as boolean.
                toggDis: function (c, i) {
                    var O = this.vRange(i);
                    O.E.children("option")[i].disabled = c;
                    if(c)O.E.children("option")[i].selected = false;
                    if(!O.mob)O.optDiv.find("ul.options li").eq(i).toggleClass("disabled", c).removeClass("selected");
                    O.setText();
                },

                // toggle disable/enable on complete select control
                toggSumo: function(val) {
                    var O = this;
                    O.enabled = val;
                    O.select.toggleClass("disabled", val);

                    if (val) {
                        O.E.attr("disabled", "disabled");
                        O.select.removeAttr("tabindex");
                    }
                    else{
                        O.E.removeAttr("disabled");
                        O.select.attr("tabindex","0");
                    }

                    return O;
                },

                //toggles alloption on c as boolean.
                toggSelAll: function (c) {
                    var O = this;
                    O.E.find("option").each(function (ix, el) {
                        if (O.E.find("option")[$(this).index()].disabled) return;
                        O.E.find("option")[$(this).index()].selected = c;
                        if (!O.mob)
							O.optDiv.find("ul.options li").eq($(this).index()).toggleClass("selected", c);
                        O.setText();
                    });
                    if(!O.mob && settings.selectAll)O.selAll.removeClass("partial").toggleClass("selected",c);
                },

                /* outside accessibility options
                   which can be accessed from the element instance.
                */
                reload:function(){
                    var elm = this.unload();
                    return $(elm).sumoSelect(settings);
                },

                unload: function () {
                    var O = this;
                    O.select.before(O.E);
                    O.E.show();

                    if (settings.outputAsCSV && O.is_multi && O.select.find("input.hidden-input").length) {
                        O.E.attr("name", O.select.find("input.hidden-input").attr("name")); // restore the name;
                    }
                    O.select.remove();
                    delete selObj.sumo;
                    return selObj;
                },

                //## add a new option to select at a given index.
                add: function (val, txt, i) {
                    if (typeof val == "undefined") throw "No value to add"

                    var O = this;
                    opts=O.E.children("option")
                    if (typeof txt == "number") { i = txt; txt = val; }
                    if (typeof txt == "undefined") { txt = val; }

                    opt = $("<option></option>").val(val).html(txt);

                    if (opts.length < i) throw "index out of bounds"

                    if (typeof i == "undefined" || opts.length == i) { // add it to the last if given index is last no or no index provides.
                        O.E.append(opt);
                        if(!O.mob)O.createLi(opt);
                    }
                    else {
                        opts.eq(i).before(opt);
                        if(!O.mob)O.createLi(opt, i);
                    }

                    return selObj;
                },

                //## removes an item at a given index.
                remove: function (i) {
                    var O = this.vRange(i);
                    O.E.children("option").eq(i).remove();
                    if(!O.mob)O.optDiv.find("ul.options li").eq(i).remove();
                    O.setText();
                },

                //## Select an item at a given index.
                selectItem: function (i) { this.toggSel(true, i); },

                //## UnSelect an iten at a given index.
                unSelectItem: function (i) { this.toggSel(false, i); },

                //## Select all items  of the select.
                selectAll: function () { this.toggSelAll(true); },

                //## UnSelect all items of the select.
                unSelectAll: function () { this.toggSelAll(false); },

                //## Disable an iten at a given index.
                disableItem: function (i) { this.toggDis(true, i) },

                //## Removes disabled an iten at a given index.
                enableItem: function (i) { this.toggDis(false, i) },

                //## New simple methods as getter and setter are not working fine in ie8-
                //## variable to check state of control if enabled or disabled.
                enabled : true,
                //## Enables the control
                enable: function(){return this.toggSumo(false)},

                //## Disables the control
                disable: function(){return this.toggSumo(true)},


                init: function () {
                    var O = this;
                    O.createElems();
                    O.setText();
                    return O
                }

            };

            selObj.sumo.init();
        });

        return ret.length == 1 ? ret[0] : ret;
    };


});

},{"jquery":214}],182:[function(require,module,exports){
/*!
 * @preserve
 *
 * Readmore.js jQuery plugin
 * Author: @jed_foster
 * Project home: http://jedfoster.github.io/Readmore.js
 * Licensed under the MIT license
 *
 * Debounce function from http://davidwalsh.name/javascript-debounce-function
 */

/* global jQuery */

(function(factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // CommonJS
    module.exports = factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function($) {
  'use strict';

  var readmore = 'readmore',
      defaults = {
        speed: 100,
        collapsedHeight: 200,
        heightMargin: 16,
        moreLink: '<a href="#">Read More</a>',
        lessLink: '<a href="#">Close</a>',
        embedCSS: true,
        blockCSS: 'display: block; width: 100%;',
        startOpen: false,

        // callbacks
        beforeToggle: function(){},
        afterToggle: function(){}
      },
      cssEmbedded = {},
      uniqueIdCounter = 0;

  function debounce(func, wait, immediate) {
    var timeout;

    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if (! immediate) {
          func.apply(context, args);
        }
      };
      var callNow = immediate && !timeout;

      clearTimeout(timeout);
      timeout = setTimeout(later, wait);

      if (callNow) {
        func.apply(context, args);
      }
    };
  }

  function uniqueId(prefix) {
    var id = ++uniqueIdCounter;

    return String(prefix == null ? 'rmjs-' : prefix) + id;
  }

  function setBoxHeights(element) {
    var el = element.clone().css({
          height: 'auto',
          width: element.width(),
          maxHeight: 'none',
          overflow: 'hidden'
        }).insertAfter(element),
        expandedHeight = el.outerHeight(),
        cssMaxHeight = parseInt(el.css({maxHeight: ''}).css('max-height').replace(/[^-\d\.]/g, ''), 10),
        defaultHeight = element.data('defaultHeight');

    el.remove();

    var collapsedHeight = cssMaxHeight || element.data('collapsedHeight') || defaultHeight;

    // Store our measurements.
    element.data({
      expandedHeight: expandedHeight,
      maxHeight: cssMaxHeight,
      collapsedHeight: collapsedHeight
    })
    // and disable any `max-height` property set in CSS
    .css({
      maxHeight: 'none'
    });
  }

  var resizeBoxes = debounce(function() {
    $('[data-readmore]').each(function() {
      var current = $(this),
          isExpanded = (current.attr('aria-expanded') === 'true');

      setBoxHeights(current);

      current.css({
        height: current.data( (isExpanded ? 'expandedHeight' : 'collapsedHeight') )
      });
    });
  }, 100);

  function embedCSS(options) {
    if (! cssEmbedded[options.selector]) {
      var styles = ' ';

      if (options.embedCSS && options.blockCSS !== '') {
        styles += options.selector + ' + [data-readmore-toggle], ' +
          options.selector + '[data-readmore]{' +
            options.blockCSS +
          '}';
      }

      // Include the transition CSS even if embedCSS is false
      styles += options.selector + '[data-readmore]{' +
        'transition: height ' + options.speed + 'ms;' +
        'overflow: hidden;' +
      '}';

      (function(d, u) {
        var css = d.createElement('style');
        css.type = 'text/css';

        if (css.styleSheet) {
          css.styleSheet.cssText = u;
        }
        else {
          css.appendChild(d.createTextNode(u));
        }

        d.getElementsByTagName('head')[0].appendChild(css);
      }(document, styles));

      cssEmbedded[options.selector] = true;
    }
  }

  function Readmore(element, options) {
    this.element = element;

    this.options = $.extend({}, defaults, options);

    embedCSS(this.options);

    this._defaults = defaults;
    this._name = readmore;

    this.init();

    // IE8 chokes on `window.addEventListener`, so need to test for support.
    if (window.addEventListener) {
      // Need to resize boxes when the page has fully loaded.
      window.addEventListener('load', resizeBoxes);
      window.addEventListener('resize', resizeBoxes);
    }
    else {
      window.attachEvent('load', resizeBoxes);
      window.attachEvent('resize', resizeBoxes);
    }
  }


  Readmore.prototype = {
    init: function() {
      var current = $(this.element);

      current.data({
        defaultHeight: this.options.collapsedHeight,
        heightMargin: this.options.heightMargin
      });

      setBoxHeights(current);

      var collapsedHeight = current.data('collapsedHeight'),
          heightMargin = current.data('heightMargin');

      if (current.outerHeight(true) <= collapsedHeight + heightMargin) {
        // The block is shorter than the limit, so there's no need to truncate it.
        return true;
      }
      else {
        var id = current.attr('id') || uniqueId(),
            useLink = this.options.startOpen ? this.options.lessLink : this.options.moreLink;

        current.attr({
          'data-readmore': '',
          'aria-expanded': this.options.startOpen,
          'id': id
        });

        current.after($(useLink)
          .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, current[0], event);
            };
          })(this))
          .attr({
            'data-readmore-toggle': '',
            'aria-controls': id
          }));

        if (! this.options.startOpen) {
          current.css({
            height: collapsedHeight
          });
        }
      }
    },

    toggle: function(trigger, element, event) {
      if (event) {
        event.preventDefault();
      }

      if (! trigger) {
        trigger = $('[aria-controls="' + _this.element.id + '"]')[0];
      }

      if (! element) {
        element = _this.element;
      }

      var $element = $(element),
          newHeight = '',
          newLink = '',
          expanded = false,
          collapsedHeight = $element.data('collapsedHeight');

      if ($element.height() <= collapsedHeight) {
        newHeight = $element.data('expandedHeight') + 'px';
        newLink = 'lessLink';
        expanded = true;
      }
      else {
        newHeight = collapsedHeight;
        newLink = 'moreLink';
      }

      // Fire beforeToggle callback
      // Since we determined the new "expanded" state above we're now out of sync
      // with our true current state, so we need to flip the value of `expanded`
      this.options.beforeToggle(trigger, $element, ! expanded);

      $element.css({'height': newHeight});

      // Fire afterToggle callback
      $element.on('transitionend', (function(_this) {
        return function() {
          _this.options.afterToggle(trigger, $element, expanded);

          $(this).attr({
            'aria-expanded': expanded
          }).off('transitionend');
        }
      })(this));

      $(trigger).replaceWith($(this.options[newLink])
        .on('click', (function(_this) {
            return function(event) {
              _this.toggle(this, element, event);
            };
          })(this))
        .attr({
          'data-readmore-toggle': '',
          'aria-controls': $element.attr('id')
        }));
    },

    destroy: function() {
      $(this.element).each(function() {
        var current = $(this);

        current.attr({
          'data-readmore': null,
          'aria-expanded': null
        })
          .css({
            maxHeight: '',
            height: ''
          })
          .next('[data-readmore-toggle]')
          .remove();

        current.removeData();
      });
    }
  };


  $.fn.readmore = function(options) {
    var args = arguments,
        selector = this.selector;

    options = options || {};

    if (typeof options === 'object') {
      return this.each(function() {
        if ($.data(this, 'plugin_' + readmore)) {
          var instance = $.data(this, 'plugin_' + readmore);
          instance.destroy.apply(instance);
        }

        options.selector = selector;

        $.data(this, 'plugin_' + readmore, new Readmore(this, options));
      });
    }
    else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
      return this.each(function () {
        var instance = $.data(this, 'plugin_' + readmore);
        if (instance instanceof Readmore && typeof instance[options] === 'function') {
          instance[options].apply(instance, Array.prototype.slice.call(args, 1));
        }
      });
    }
  };

}));


},{"jquery":214}],183:[function(require,module,exports){
(function (factory) {
    "use strict";
    if (typeof define === "function" && define.amd) {
        // AMD anonymous module
        define(["knockout"], factory);
    } else if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        // CommonJS module
        var ko = require("knockout");
        var Sortable = require("sortable");
        factory(ko, Sortable);
    } else {
        // No module loader (plain <script> tag) - put directly in global namespace
        factory(window.ko);
    }
})(function (ko, Sortable) {
    "use strict";

    var init = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {

        var options = buildOptions(valueAccessor, sortableOptions);

        //It's seems that we cannot update the eventhandlers after we've created the sortable, so define them in init instead of update
        ['onStart', 'onEnd', 'onRemove', 'onAdd', 'onUpdate', 'onSort', 'onFilter'].forEach(function (e) {
            if (options[e] || eventHandlers[e])
                options[e] = function (eventType, parentVM, parentBindings, handler, e) {
                    var itemVM = ko.dataFor(e.item),
                        //All of the bindings on the parent element
                        bindings = ko.utils.peekObservable(parentBindings()),
                        //The binding options for the draggable/sortable binding of the parent element
                        bindingHandlerBinding = bindings.sortable || bindings.draggable,
                        //The collection that we should modify
                        collection = bindingHandlerBinding.collection || bindingHandlerBinding.foreach;
                    if (handler)
                        handler(e, itemVM, parentVM, collection, bindings);
                    if (eventHandlers[eventType])
                        eventHandlers[eventType](e, itemVM, parentVM, collection, bindings);
                }.bind(undefined, e, viewModel, allBindings, options[e]);
        });

        var sortableElement = Sortable.create(element, options);

        //Destroy the sortable if knockout disposes the element it's connected to
        ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
            sortableElement.destroy();
        });
        return ko.bindingHandlers.template.init(element, valueAccessor);
    },
    update = function (element, valueAccessor, allBindings, viewModel, bindingContext, sortableOptions) {

        //There seems to be some problems with updating the options of a sortable
        //Tested to change eventhandlers and the group options without any luck

        return ko.bindingHandlers.template.update(element, valueAccessor, allBindings, viewModel, bindingContext);
    },
    eventHandlers = (function (handlers) {

        var moveOperations = [],
            tryMoveOperation = function (e, itemVM, parentVM, collection, parentBindings) {
                //A move operation is the combination of a add and remove event, this is to make sure that we have both the target and origin collections
                var currentOperation = { event: e, itemVM: itemVM, parentVM: parentVM, collection: collection, parentBindings: parentBindings },
                    existingOperation = moveOperations.filter(function (op) {
                        return op.itemVM === currentOperation.itemVM;
                    })[0];

                if (!existingOperation) {
                    moveOperations.push(currentOperation);
                }
                else {
                    //We're finishing the operation and already have a handle on the operation item meaning that it's safe to remove it
                    moveOperations.splice(moveOperations.indexOf(existingOperation), 1);

                    var removeOperation = currentOperation.event.type === 'remove' ? currentOperation : existingOperation,
                        addOperation = currentOperation.event.type === 'add' ? currentOperation : existingOperation;

                    moveItem(itemVM, removeOperation.collection, addOperation.collection, addOperation.event.clone, addOperation.event);
                }
            },
            //Moves an item from the to (collection to from (collection), these can be references to the same collection which means it's a sort,
            //clone indicates if we should move or copy the item into the new collection
            moveItem = function (itemVM, from, to, clone, e) {
                //Unwrapping this allows us to manipulate the actual array
                var fromArray = from(),
                    //It's not certain that the items actual index is the same as the index reported by sortable due to filtering etc.
                    originalIndex = fromArray.indexOf(itemVM),
                    newIndex = e.newIndex;

                if (e.item.previousElementSibling)
                    newIndex = fromArray.indexOf(ko.dataFor(e.item.previousElementSibling));
                if (originalIndex > newIndex)
                    newIndex = newIndex + 1;

                //Remove sortables "unbound" element
                e.item.parentNode.removeChild(e.item);

                //This splice is necessary for both clone and move/sort
                //In sort/move since it shouldn't be at this index/in this array anymore
                //In clone since we have to work around knockouts valuHasMutated when manipulating arrays and avoid a "unbound" item added by sortable
                fromArray.splice(originalIndex, 1);
                //Update the array, this will also remove sortables "unbound" clone
                from.valueHasMutated();
                if (clone && from !== to) {
                    //Readd the item
                    fromArray.splice(originalIndex, 0, itemVM);
                    //Force knockout to update
                    from.valueHasMutated();
                }
                //Insert the item on its new position
                to().splice(newIndex, 0, itemVM);
                //Make sure to tell knockout that we've modified the actual array.
                to.valueHasMutated();
            };

        handlers.onRemove = tryMoveOperation;
        handlers.onAdd = tryMoveOperation;
        handlers.onUpdate = function (e, itemVM, parentVM, collection, parentBindings) {
            //This will be performed as a sort since the to/from collections reference the same collection and clone is set to false
            moveItem(itemVM, collection, collection, false, e);
        };

        return handlers;
    })({}),
    //bindingOptions are the options set in the "data-bind" attribute in the ui.
    //options are custom options, for instance draggable/sortable specific options
    buildOptions = function (bindingOptions, options) {
        //deep clone/copy of properties from the "from" argument onto the "into" argument and returns the modified "into"
        var merge = function (into, from) {
            for (var prop in from) {
                if (Object.prototype.toString.call(from[prop]) === '[object Object]') {
                    if (Object.prototype.toString.call(into[prop]) !== '[object Object]') {
                        into[prop] = {};
                    }
                    into[prop] = merge(into[prop], from[prop]);
                }
                else
                    into[prop] = from[prop];
            }

            return into;
        },
        //unwrap the supplied options
        unwrappedOptions = ko.utils.peekObservable(bindingOptions()).options || {};

        //Make sure that we don't modify the provided settings object
        options = merge({}, options);

        //group is handled differently since we should both allow to change a draggable to a sortable (and vice versa),
        //but still be able to set a name on a draggable without it becoming a drop target.
        if (unwrappedOptions.group && Object.prototype.toString.call(unwrappedOptions.group) !== '[object Object]') {
            //group property is a name string declaration, convert to object.
            unwrappedOptions.group = { name: unwrappedOptions.group };
        }

        return merge(options, unwrappedOptions);
    };

    ko.bindingHandlers.draggable = {
        sortableOptions: {
            group: { pull: 'clone', put: false },
            sort: false
        },
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.draggable.sortableOptions);
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.draggable.sortableOptions);
        }
    };

    ko.bindingHandlers.sortable = {
        sortableOptions: {
            group: { pull: true, put: true }
        },
        init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return init(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.sortable.sortableOptions);
        },
        update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            return update(element, valueAccessor, allBindings, viewModel, bindingContext, ko.bindingHandlers.sortable.sortableOptions);
        }
    };

});

},{"knockout":191,"sortable":196}],184:[function(require,module,exports){
/**
 * @preserve
 * Project: Bootstrap Hover Dropdown
 * Author: Cameron Spear
 * Version: v2.2.1
 * Contributors: Mattia Larentis
 * Dependencies: Bootstrap's Dropdown plugin, jQuery
 * Description: A simple plugin to enable Bootstrap dropdowns to active on hover and provide a nice user experience.
 * License: MIT
 * Homepage: http://cameronspear.com/blog/bootstrap-dropdown-on-hover-plugin/
 */
;(function ($, window, undefined) {
    // outside the scope of the jQuery plugin to
    // keep track of all dropdowns
    var $allDropdowns = $();

    // if instantlyCloseOthers is true, then it will instantly
    // shut other nav items when a new one is hovered over
    $.fn.dropdownHover = function (options) {
        // don't do anything if touch is supported
        // (plugin causes some issues on mobile)
        if('ontouchstart' in document) return this; // don't want to affect chaining

        // the element we really care about
        // is the dropdown-toggle's parent
        $allDropdowns = $allDropdowns.add(this.parent());

        return this.each(function () {
            var $this = $(this),
                $parent = $this.parent(),
                defaults = {
                    delay: 500,
                    hoverDelay: 0,
                    instantlyCloseOthers: true
                },
                data = {
                    delay: $(this).data('delay'),
                    hoverDelay: $(this).data('hover-delay'),
                    instantlyCloseOthers: $(this).data('close-others')
                },
                showEvent   = 'show.bs.dropdown',
                hideEvent   = 'hide.bs.dropdown',
                // shownEvent  = 'shown.bs.dropdown',
                // hiddenEvent = 'hidden.bs.dropdown',
                settings = $.extend(true, {}, defaults, options, data),
                timeout, timeoutHover;

            $parent.hover(function (event) {
                // so a neighbor can't open the dropdown
                if($parent.hasClass('open') && !$this.is(event.target)) {
                    // stop this event, stop executing any code
                    // in this callback but continue to propagate
                    return true;
                }

                openDropdown(event);
            }, function () {
                // clear timer for hover event
                window.clearTimeout(timeoutHover)
                timeout = window.setTimeout(function () {
                    $this.attr('aria-expanded', 'false');
                    $parent.removeClass('open');
                    $this.trigger(hideEvent);
                }, settings.delay);
            });

            // this helps with button groups!
            $this.hover(function (event) {
                // this helps prevent a double event from firing.
                // see https://github.com/CWSpear/bootstrap-hover-dropdown/issues/55
                if(!$parent.hasClass('open') && !$parent.is(event.target)) {
                    // stop this event, stop executing any code
                    // in this callback but continue to propagate
                    return true;
                }

                openDropdown(event);
            });

            // handle submenus
            $parent.find('.dropdown-submenu').each(function (){
                var $this = $(this);
                var subTimeout;
                $this.hover(function () {
                    window.clearTimeout(subTimeout);
                    $this.children('.dropdown-menu').show();
                    // always close submenu siblings instantly
                    $this.siblings().children('.dropdown-menu').hide();
                }, function () {
                    var $submenu = $this.children('.dropdown-menu');
                    subTimeout = window.setTimeout(function () {
                        $submenu.hide();
                    }, settings.delay);
                });
            });

            function openDropdown(event) {
                if($this.parents(".navbar").find(".navbar-toggle").is(":visible")) {
                    // If we're inside a navbar, don't do anything when the
                    // navbar is collapsed, as it makes the navbar pretty unusable.
                    return;
                }

                // clear dropdown timeout here so it doesnt close before it should
                window.clearTimeout(timeout);
                // restart hover timer
                window.clearTimeout(timeoutHover);
                
                // delay for hover event.  
                timeoutHover = window.setTimeout(function () {
                    $allDropdowns.find(':focus').blur();

                    if(settings.instantlyCloseOthers === true)
                        $allDropdowns.removeClass('open');
                    
                    // clear timer for hover event
                    window.clearTimeout(timeoutHover);
                    $this.attr('aria-expanded', 'true');
                    $parent.addClass('open');
                    $this.trigger(showEvent);
                }, settings.hoverDelay);
            }
        });
    };

    $(document).ready(function () {
        // apply dropdownHover to all elements with the data-hover="dropdown" attribute
        $('[data-hover="dropdown"]').dropdownHover();
    });
})(jQuery, window);

},{}],185:[function(require,module,exports){
/*!
 * Bootstrap v3.3.6 (http://getbootstrap.com)
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under the MIT license
 */

if (typeof jQuery === 'undefined') {
  throw new Error('Bootstrap\'s JavaScript requires jQuery')
}

+function ($) {
  'use strict';
  var version = $.fn.jquery.split(' ')[0].split('.')
  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) {
    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')
  }
}(jQuery);

/* ========================================================================
 * Bootstrap: transition.js v3.3.6
 * http://getbootstrap.com/javascript/#transitions
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
  // ============================================================

  function transitionEnd() {
    var el = document.createElement('bootstrap')

    var transEndEventNames = {
      WebkitTransition : 'webkitTransitionEnd',
      MozTransition    : 'transitionend',
      OTransition      : 'oTransitionEnd otransitionend',
      transition       : 'transitionend'
    }

    for (var name in transEndEventNames) {
      if (el.style[name] !== undefined) {
        return { end: transEndEventNames[name] }
      }
    }

    return false // explicit for ie8 (  ._.)
  }

  // http://blog.alexmaccaw.com/css-transitions
  $.fn.emulateTransitionEnd = function (duration) {
    var called = false
    var $el = this
    $(this).one('bsTransitionEnd', function () { called = true })
    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
    setTimeout(callback, duration)
    return this
  }

  $(function () {
    $.support.transition = transitionEnd()

    if (!$.support.transition) return

    $.event.special.bsTransitionEnd = {
      bindType: $.support.transition.end,
      delegateType: $.support.transition.end,
      handle: function (e) {
        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
      }
    }
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: alert.js v3.3.6
 * http://getbootstrap.com/javascript/#alerts
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // ALERT CLASS DEFINITION
  // ======================

  var dismiss = '[data-dismiss="alert"]'
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }

  Alert.VERSION = '3.3.6'

  Alert.TRANSITION_DURATION = 150

  Alert.prototype.close = function (e) {
    var $this    = $(this)
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = $(selector)

    if (e) e.preventDefault()

    if (!$parent.length) {
      $parent = $this.closest('.alert')
    }

    $parent.trigger(e = $.Event('close.bs.alert'))

    if (e.isDefaultPrevented()) return

    $parent.removeClass('in')

    function removeElement() {
      // detach from parent, fire event then clean up data
      $parent.detach().trigger('closed.bs.alert').remove()
    }

    $.support.transition && $parent.hasClass('fade') ?
      $parent
        .one('bsTransitionEnd', removeElement)
        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
      removeElement()
  }


  // ALERT PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.alert')

      if (!data) $this.data('bs.alert', (data = new Alert(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.alert

  $.fn.alert             = Plugin
  $.fn.alert.Constructor = Alert


  // ALERT NO CONFLICT
  // =================

  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }


  // ALERT DATA-API
  // ==============

  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

/* ========================================================================
 * Bootstrap: button.js v3.3.6
 * http://getbootstrap.com/javascript/#buttons
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // BUTTON PUBLIC CLASS DEFINITION
  // ==============================

  var Button = function (element, options) {
    this.$element  = $(element)
    this.options   = $.extend({}, Button.DEFAULTS, options)
    this.isLoading = false
  }

  Button.VERSION  = '3.3.6'

  Button.DEFAULTS = {
    loadingText: 'loading...'
  }

  Button.prototype.setState = function (state) {
    var d    = 'disabled'
    var $el  = this.$element
    var val  = $el.is('input') ? 'val' : 'html'
    var data = $el.data()

    state += 'Text'

    if (data.resetText == null) $el.data('resetText', $el[val]())

    // push to event loop to allow forms to submit
    setTimeout($.proxy(function () {
      $el[val](data[state] == null ? this.options[state] : data[state])

      if (state == 'loadingText') {
        this.isLoading = true
        $el.addClass(d).attr(d, d)
      } else if (this.isLoading) {
        this.isLoading = false
        $el.removeClass(d).removeAttr(d)
      }
    }, this), 0)
  }

  Button.prototype.toggle = function () {
    var changed = true
    var $parent = this.$element.closest('[data-toggle="buttons"]')

    if ($parent.length) {
      var $input = this.$element.find('input')
      if ($input.prop('type') == 'radio') {
        if ($input.prop('checked')) changed = false
        $parent.find('.active').removeClass('active')
        this.$element.addClass('active')
      } else if ($input.prop('type') == 'checkbox') {
        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
        this.$element.toggleClass('active')
      }
      $input.prop('checked', this.$element.hasClass('active'))
      if (changed) $input.trigger('change')
    } else {
      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
      this.$element.toggleClass('active')
    }
  }


  // BUTTON PLUGIN DEFINITION
  // ========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.button')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.button', (data = new Button(this, options)))

      if (option == 'toggle') data.toggle()
      else if (option) data.setState(option)
    })
  }

  var old = $.fn.button

  $.fn.button             = Plugin
  $.fn.button.Constructor = Button


  // BUTTON NO CONFLICT
  // ==================

  $.fn.button.noConflict = function () {
    $.fn.button = old
    return this
  }


  // BUTTON DATA-API
  // ===============

  $(document)
    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      var $btn = $(e.target)
      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
      Plugin.call($btn, 'toggle')
      if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
    })
    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
    })

}(jQuery);

/* ========================================================================
 * Bootstrap: carousel.js v3.3.6
 * http://getbootstrap.com/javascript/#carousel
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // CAROUSEL CLASS DEFINITION
  // =========================

  var Carousel = function (element, options) {
    this.$element    = $(element)
    this.$indicators = this.$element.find('.carousel-indicators')
    this.options     = options
    this.paused      = null
    this.sliding     = null
    this.interval    = null
    this.$active     = null
    this.$items      = null

    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))

    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
  }

  Carousel.VERSION  = '3.3.6'

  Carousel.TRANSITION_DURATION = 600

  Carousel.DEFAULTS = {
    interval: 5000,
    pause: 'hover',
    wrap: true,
    keyboard: true
  }

  Carousel.prototype.keydown = function (e) {
    if (/input|textarea/i.test(e.target.tagName)) return
    switch (e.which) {
      case 37: this.prev(); break
      case 39: this.next(); break
      default: return
    }

    e.preventDefault()
  }

  Carousel.prototype.cycle = function (e) {
    e || (this.paused = false)

    this.interval && clearInterval(this.interval)

    this.options.interval
      && !this.paused
      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))

    return this
  }

  Carousel.prototype.getItemIndex = function (item) {
    this.$items = item.parent().children('.item')
    return this.$items.index(item || this.$active)
  }

  Carousel.prototype.getItemForDirection = function (direction, active) {
    var activeIndex = this.getItemIndex(active)
    var willWrap = (direction == 'prev' && activeIndex === 0)
                || (direction == 'next' && activeIndex == (this.$items.length - 1))
    if (willWrap && !this.options.wrap) return active
    var delta = direction == 'prev' ? -1 : 1
    var itemIndex = (activeIndex + delta) % this.$items.length
    return this.$items.eq(itemIndex)
  }

  Carousel.prototype.to = function (pos) {
    var that        = this
    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))

    if (pos > (this.$items.length - 1) || pos < 0) return

    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
    if (activeIndex == pos) return this.pause().cycle()

    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
  }

  Carousel.prototype.pause = function (e) {
    e || (this.paused = true)

    if (this.$element.find('.next, .prev').length && $.support.transition) {
      this.$element.trigger($.support.transition.end)
      this.cycle(true)
    }

    this.interval = clearInterval(this.interval)

    return this
  }

  Carousel.prototype.next = function () {
    if (this.sliding) return
    return this.slide('next')
  }

  Carousel.prototype.prev = function () {
    if (this.sliding) return
    return this.slide('prev')
  }

  Carousel.prototype.slide = function (type, next) {
    var $active   = this.$element.find('.item.active')
    var $next     = next || this.getItemForDirection(type, $active)
    var isCycling = this.interval
    var direction = type == 'next' ? 'left' : 'right'
    var that      = this

    if ($next.hasClass('active')) return (this.sliding = false)

    var relatedTarget = $next[0]
    var slideEvent = $.Event('slide.bs.carousel', {
      relatedTarget: relatedTarget,
      direction: direction
    })
    this.$element.trigger(slideEvent)
    if (slideEvent.isDefaultPrevented()) return

    this.sliding = true

    isCycling && this.pause()

    if (this.$indicators.length) {
      this.$indicators.find('.active').removeClass('active')
      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
      $nextIndicator && $nextIndicator.addClass('active')
    }

    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
    if ($.support.transition && this.$element.hasClass('slide')) {
      $next.addClass(type)
      $next[0].offsetWidth // force reflow
      $active.addClass(direction)
      $next.addClass(direction)
      $active
        .one('bsTransitionEnd', function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
          that.sliding = false
          setTimeout(function () {
            that.$element.trigger(slidEvent)
          }, 0)
        })
        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
    } else {
      $active.removeClass('active')
      $next.addClass('active')
      this.sliding = false
      this.$element.trigger(slidEvent)
    }

    isCycling && this.cycle()

    return this
  }


  // CAROUSEL PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.carousel')
      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
      var action  = typeof option == 'string' ? option : options.slide

      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
      if (typeof option == 'number') data.to(option)
      else if (action) data[action]()
      else if (options.interval) data.pause().cycle()
    })
  }

  var old = $.fn.carousel

  $.fn.carousel             = Plugin
  $.fn.carousel.Constructor = Carousel


  // CAROUSEL NO CONFLICT
  // ====================

  $.fn.carousel.noConflict = function () {
    $.fn.carousel = old
    return this
  }


  // CAROUSEL DATA-API
  // =================

  var clickHandler = function (e) {
    var href
    var $this   = $(this)
    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
    if (!$target.hasClass('carousel')) return
    var options = $.extend({}, $target.data(), $this.data())
    var slideIndex = $this.attr('data-slide-to')
    if (slideIndex) options.interval = false

    Plugin.call($target, options)

    if (slideIndex) {
      $target.data('bs.carousel').to(slideIndex)
    }

    e.preventDefault()
  }

  $(document)
    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)

  $(window).on('load', function () {
    $('[data-ride="carousel"]').each(function () {
      var $carousel = $(this)
      Plugin.call($carousel, $carousel.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: collapse.js v3.3.6
 * http://getbootstrap.com/javascript/#collapse
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // COLLAPSE PUBLIC CLASS DEFINITION
  // ================================

  var Collapse = function (element, options) {
    this.$element      = $(element)
    this.options       = $.extend({}, Collapse.DEFAULTS, options)
    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
    this.transitioning = null

    if (this.options.parent) {
      this.$parent = this.getParent()
    } else {
      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
    }

    if (this.options.toggle) this.toggle()
  }

  Collapse.VERSION  = '3.3.6'

  Collapse.TRANSITION_DURATION = 350

  Collapse.DEFAULTS = {
    toggle: true
  }

  Collapse.prototype.dimension = function () {
    var hasWidth = this.$element.hasClass('width')
    return hasWidth ? 'width' : 'height'
  }

  Collapse.prototype.show = function () {
    if (this.transitioning || this.$element.hasClass('in')) return

    var activesData
    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')

    if (actives && actives.length) {
      activesData = actives.data('bs.collapse')
      if (activesData && activesData.transitioning) return
    }

    var startEvent = $.Event('show.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    if (actives && actives.length) {
      Plugin.call(actives, 'hide')
      activesData || actives.data('bs.collapse', null)
    }

    var dimension = this.dimension()

    this.$element
      .removeClass('collapse')
      .addClass('collapsing')[dimension](0)
      .attr('aria-expanded', true)

    this.$trigger
      .removeClass('collapsed')
      .attr('aria-expanded', true)

    this.transitioning = 1

    var complete = function () {
      this.$element
        .removeClass('collapsing')
        .addClass('collapse in')[dimension]('')
      this.transitioning = 0
      this.$element
        .trigger('shown.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    var scrollSize = $.camelCase(['scroll', dimension].join('-'))

    this.$element
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
  }

  Collapse.prototype.hide = function () {
    if (this.transitioning || !this.$element.hasClass('in')) return

    var startEvent = $.Event('hide.bs.collapse')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    var dimension = this.dimension()

    this.$element[dimension](this.$element[dimension]())[0].offsetHeight

    this.$element
      .addClass('collapsing')
      .removeClass('collapse in')
      .attr('aria-expanded', false)

    this.$trigger
      .addClass('collapsed')
      .attr('aria-expanded', false)

    this.transitioning = 1

    var complete = function () {
      this.transitioning = 0
      this.$element
        .removeClass('collapsing')
        .addClass('collapse')
        .trigger('hidden.bs.collapse')
    }

    if (!$.support.transition) return complete.call(this)

    this.$element
      [dimension](0)
      .one('bsTransitionEnd', $.proxy(complete, this))
      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
  }

  Collapse.prototype.toggle = function () {
    this[this.$element.hasClass('in') ? 'hide' : 'show']()
  }

  Collapse.prototype.getParent = function () {
    return $(this.options.parent)
      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
      .each($.proxy(function (i, element) {
        var $element = $(element)
        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
      }, this))
      .end()
  }

  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
    var isOpen = $element.hasClass('in')

    $element.attr('aria-expanded', isOpen)
    $trigger
      .toggleClass('collapsed', !isOpen)
      .attr('aria-expanded', isOpen)
  }

  function getTargetFromTrigger($trigger) {
    var href
    var target = $trigger.attr('data-target')
      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7

    return $(target)
  }


  // COLLAPSE PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.collapse')
      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.collapse

  $.fn.collapse             = Plugin
  $.fn.collapse.Constructor = Collapse


  // COLLAPSE NO CONFLICT
  // ====================

  $.fn.collapse.noConflict = function () {
    $.fn.collapse = old
    return this
  }


  // COLLAPSE DATA-API
  // =================

  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
    var $this   = $(this)

    if (!$this.attr('data-target')) e.preventDefault()

    var $target = getTargetFromTrigger($this)
    var data    = $target.data('bs.collapse')
    var option  = data ? 'toggle' : $this.data()

    Plugin.call($target, option)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: dropdown.js v3.3.6
 * http://getbootstrap.com/javascript/#dropdowns
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // DROPDOWN CLASS DEFINITION
  // =========================

  var backdrop = '.dropdown-backdrop'
  var toggle   = '[data-toggle="dropdown"]'
  var Dropdown = function (element) {
    $(element).on('click.bs.dropdown', this.toggle)
  }

  Dropdown.VERSION = '3.3.6'

  function getParent($this) {
    var selector = $this.attr('data-target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    var $parent = selector && $(selector)

    return $parent && $parent.length ? $parent : $this.parent()
  }

  function clearMenus(e) {
    if (e && e.which === 3) return
    $(backdrop).remove()
    $(toggle).each(function () {
      var $this         = $(this)
      var $parent       = getParent($this)
      var relatedTarget = { relatedTarget: this }

      if (!$parent.hasClass('open')) return

      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return

      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this.attr('aria-expanded', 'false')
      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
    })
  }

  Dropdown.prototype.toggle = function (e) {
    var $this = $(this)

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    clearMenus()

    if (!isActive) {
      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
        // if mobile we use a backdrop because click events don't delegate
        $(document.createElement('div'))
          .addClass('dropdown-backdrop')
          .insertAfter($(this))
          .on('click', clearMenus)
      }

      var relatedTarget = { relatedTarget: this }
      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))

      if (e.isDefaultPrevented()) return

      $this
        .trigger('focus')
        .attr('aria-expanded', 'true')

      $parent
        .toggleClass('open')
        .trigger($.Event('shown.bs.dropdown', relatedTarget))
    }

    return false
  }

  Dropdown.prototype.keydown = function (e) {
    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return

    var $this = $(this)

    e.preventDefault()
    e.stopPropagation()

    if ($this.is('.disabled, :disabled')) return

    var $parent  = getParent($this)
    var isActive = $parent.hasClass('open')

    if (!isActive && e.which != 27 || isActive && e.which == 27) {
      if (e.which == 27) $parent.find(toggle).trigger('focus')
      return $this.trigger('click')
    }

    var desc = ' li:not(.disabled):visible a'
    var $items = $parent.find('.dropdown-menu' + desc)

    if (!$items.length) return

    var index = $items.index(e.target)

    if (e.which == 38 && index > 0)                 index--         // up
    if (e.which == 40 && index < $items.length - 1) index++         // down
    if (!~index)                                    index = 0

    $items.eq(index).trigger('focus')
  }


  // DROPDOWN PLUGIN DEFINITION
  // ==========================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.dropdown')

      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  var old = $.fn.dropdown

  $.fn.dropdown             = Plugin
  $.fn.dropdown.Constructor = Dropdown


  // DROPDOWN NO CONFLICT
  // ====================

  $.fn.dropdown.noConflict = function () {
    $.fn.dropdown = old
    return this
  }


  // APPLY TO STANDARD DROPDOWN ELEMENTS
  // ===================================

  $(document)
    .on('click.bs.dropdown.data-api', clearMenus)
    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)

}(jQuery);

/* ========================================================================
 * Bootstrap: modal.js v3.3.6
 * http://getbootstrap.com/javascript/#modals
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // MODAL CLASS DEFINITION
  // ======================

  var Modal = function (element, options) {
    this.options             = options
    this.$body               = $(document.body)
    this.$element            = $(element)
    this.$dialog             = this.$element.find('.modal-dialog')
    this.$backdrop           = null
    this.isShown             = null
    this.originalBodyPad     = null
    this.scrollbarWidth      = 0
    this.ignoreBackdropClick = false

    if (this.options.remote) {
      this.$element
        .find('.modal-content')
        .load(this.options.remote, $.proxy(function () {
          this.$element.trigger('loaded.bs.modal')
        }, this))
    }
  }

  Modal.VERSION  = '3.3.6'

  Modal.TRANSITION_DURATION = 300
  Modal.BACKDROP_TRANSITION_DURATION = 150

  Modal.DEFAULTS = {
    backdrop: true,
    keyboard: true,
    show: true
  }

  Modal.prototype.toggle = function (_relatedTarget) {
    return this.isShown ? this.hide() : this.show(_relatedTarget)
  }

  Modal.prototype.show = function (_relatedTarget) {
    var that = this
    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })

    this.$element.trigger(e)

    if (this.isShown || e.isDefaultPrevented()) return

    this.isShown = true

    this.checkScrollbar()
    this.setScrollbar()
    this.$body.addClass('modal-open')

    this.escape()
    this.resize()

    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))

    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
      })
    })

    this.backdrop(function () {
      var transition = $.support.transition && that.$element.hasClass('fade')

      if (!that.$element.parent().length) {
        that.$element.appendTo(that.$body) // don't move modals dom position
      }

      that.$element
        .show()
        .scrollTop(0)

      that.adjustDialog()

      if (transition) {
        that.$element[0].offsetWidth // force reflow
      }

      that.$element.addClass('in')

      that.enforceFocus()

      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })

      transition ?
        that.$dialog // wait for modal to slide in
          .one('bsTransitionEnd', function () {
            that.$element.trigger('focus').trigger(e)
          })
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
        that.$element.trigger('focus').trigger(e)
    })
  }

  Modal.prototype.hide = function (e) {
    if (e) e.preventDefault()

    e = $.Event('hide.bs.modal')

    this.$element.trigger(e)

    if (!this.isShown || e.isDefaultPrevented()) return

    this.isShown = false

    this.escape()
    this.resize()

    $(document).off('focusin.bs.modal')

    this.$element
      .removeClass('in')
      .off('click.dismiss.bs.modal')
      .off('mouseup.dismiss.bs.modal')

    this.$dialog.off('mousedown.dismiss.bs.modal')

    $.support.transition && this.$element.hasClass('fade') ?
      this.$element
        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
      this.hideModal()
  }

  Modal.prototype.enforceFocus = function () {
    $(document)
      .off('focusin.bs.modal') // guard against infinite focus loop
      .on('focusin.bs.modal', $.proxy(function (e) {
        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
          this.$element.trigger('focus')
        }
      }, this))
  }

  Modal.prototype.escape = function () {
    if (this.isShown && this.options.keyboard) {
      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
        e.which == 27 && this.hide()
      }, this))
    } else if (!this.isShown) {
      this.$element.off('keydown.dismiss.bs.modal')
    }
  }

  Modal.prototype.resize = function () {
    if (this.isShown) {
      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
    } else {
      $(window).off('resize.bs.modal')
    }
  }

  Modal.prototype.hideModal = function () {
    var that = this
    this.$element.hide()
    this.backdrop(function () {
      that.$body.removeClass('modal-open')
      that.resetAdjustments()
      that.resetScrollbar()
      that.$element.trigger('hidden.bs.modal')
    })
  }

  Modal.prototype.removeBackdrop = function () {
    this.$backdrop && this.$backdrop.remove()
    this.$backdrop = null
  }

  Modal.prototype.backdrop = function (callback) {
    var that = this
    var animate = this.$element.hasClass('fade') ? 'fade' : ''

    if (this.isShown && this.options.backdrop) {
      var doAnimate = $.support.transition && animate

      this.$backdrop = $(document.createElement('div'))
        .addClass('modal-backdrop ' + animate)
        .appendTo(this.$body)

      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
        if (this.ignoreBackdropClick) {
          this.ignoreBackdropClick = false
          return
        }
        if (e.target !== e.currentTarget) return
        this.options.backdrop == 'static'
          ? this.$element[0].focus()
          : this.hide()
      }, this))

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')

      if (!callback) return

      doAnimate ?
        this.$backdrop
          .one('bsTransitionEnd', callback)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callback()

    } else if (!this.isShown && this.$backdrop) {
      this.$backdrop.removeClass('in')

      var callbackRemove = function () {
        that.removeBackdrop()
        callback && callback()
      }
      $.support.transition && this.$element.hasClass('fade') ?
        this.$backdrop
          .one('bsTransitionEnd', callbackRemove)
          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
        callbackRemove()

    } else if (callback) {
      callback()
    }
  }

  // these following methods are used to handle overflowing modals

  Modal.prototype.handleUpdate = function () {
    this.adjustDialog()
  }

  Modal.prototype.adjustDialog = function () {
    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight

    this.$element.css({
      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
    })
  }

  Modal.prototype.resetAdjustments = function () {
    this.$element.css({
      paddingLeft: '',
      paddingRight: ''
    })
  }

  Modal.prototype.checkScrollbar = function () {
    var fullWindowWidth = window.innerWidth
    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
      var documentElementRect = document.documentElement.getBoundingClientRect()
      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
    }
    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
    this.scrollbarWidth = this.measureScrollbar()
  }

  Modal.prototype.setScrollbar = function () {
    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
    this.originalBodyPad = document.body.style.paddingRight || ''
    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
  }

  Modal.prototype.resetScrollbar = function () {
    this.$body.css('padding-right', this.originalBodyPad)
  }

  Modal.prototype.measureScrollbar = function () { // thx walsh
    var scrollDiv = document.createElement('div')
    scrollDiv.className = 'modal-scrollbar-measure'
    this.$body.append(scrollDiv)
    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
    this.$body[0].removeChild(scrollDiv)
    return scrollbarWidth
  }


  // MODAL PLUGIN DEFINITION
  // =======================

  function Plugin(option, _relatedTarget) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.modal')
      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)

      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
      if (typeof option == 'string') data[option](_relatedTarget)
      else if (options.show) data.show(_relatedTarget)
    })
  }

  var old = $.fn.modal

  $.fn.modal             = Plugin
  $.fn.modal.Constructor = Modal


  // MODAL NO CONFLICT
  // =================

  $.fn.modal.noConflict = function () {
    $.fn.modal = old
    return this
  }


  // MODAL DATA-API
  // ==============

  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
    var $this   = $(this)
    var href    = $this.attr('href')
    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())

    if ($this.is('a')) e.preventDefault()

    $target.one('show.bs.modal', function (showEvent) {
      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
      $target.one('hidden.bs.modal', function () {
        $this.is(':visible') && $this.trigger('focus')
      })
    })
    Plugin.call($target, option, this)
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tooltip.js v3.3.6
 * http://getbootstrap.com/javascript/#tooltip
 * Inspired by the original jQuery.tipsy by Jason Frame
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TOOLTIP PUBLIC CLASS DEFINITION
  // ===============================

  var Tooltip = function (element, options) {
    this.type       = null
    this.options    = null
    this.enabled    = null
    this.timeout    = null
    this.hoverState = null
    this.$element   = null
    this.inState    = null

    this.init('tooltip', element, options)
  }

  Tooltip.VERSION  = '3.3.6'

  Tooltip.TRANSITION_DURATION = 150

  Tooltip.DEFAULTS = {
    animation: true,
    placement: 'top',
    selector: false,
    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
    trigger: 'hover focus',
    title: '',
    delay: 0,
    html: false,
    container: false,
    viewport: {
      selector: 'body',
      padding: 0
    }
  }

  Tooltip.prototype.init = function (type, element, options) {
    this.enabled   = true
    this.type      = type
    this.$element  = $(element)
    this.options   = this.getOptions(options)
    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
    this.inState   = { click: false, hover: false, focus: false }

    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
    }

    var triggers = this.options.trigger.split(' ')

    for (var i = triggers.length; i--;) {
      var trigger = triggers[i]

      if (trigger == 'click') {
        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
      } else if (trigger != 'manual') {
        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'

        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
      }
    }

    this.options.selector ?
      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
      this.fixTitle()
  }

  Tooltip.prototype.getDefaults = function () {
    return Tooltip.DEFAULTS
  }

  Tooltip.prototype.getOptions = function (options) {
    options = $.extend({}, this.getDefaults(), this.$element.data(), options)

    if (options.delay && typeof options.delay == 'number') {
      options.delay = {
        show: options.delay,
        hide: options.delay
      }
    }

    return options
  }

  Tooltip.prototype.getDelegateOptions = function () {
    var options  = {}
    var defaults = this.getDefaults()

    this._options && $.each(this._options, function (key, value) {
      if (defaults[key] != value) options[key] = value
    })

    return options
  }

  Tooltip.prototype.enter = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    if (obj instanceof $.Event) {
      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
    }

    if (self.tip().hasClass('in') || self.hoverState == 'in') {
      self.hoverState = 'in'
      return
    }

    clearTimeout(self.timeout)

    self.hoverState = 'in'

    if (!self.options.delay || !self.options.delay.show) return self.show()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'in') self.show()
    }, self.options.delay.show)
  }

  Tooltip.prototype.isInStateTrue = function () {
    for (var key in this.inState) {
      if (this.inState[key]) return true
    }

    return false
  }

  Tooltip.prototype.leave = function (obj) {
    var self = obj instanceof this.constructor ?
      obj : $(obj.currentTarget).data('bs.' + this.type)

    if (!self) {
      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
      $(obj.currentTarget).data('bs.' + this.type, self)
    }

    if (obj instanceof $.Event) {
      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
    }

    if (self.isInStateTrue()) return

    clearTimeout(self.timeout)

    self.hoverState = 'out'

    if (!self.options.delay || !self.options.delay.hide) return self.hide()

    self.timeout = setTimeout(function () {
      if (self.hoverState == 'out') self.hide()
    }, self.options.delay.hide)
  }

  Tooltip.prototype.show = function () {
    var e = $.Event('show.bs.' + this.type)

    if (this.hasContent() && this.enabled) {
      this.$element.trigger(e)

      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
      if (e.isDefaultPrevented() || !inDom) return
      var that = this

      var $tip = this.tip()

      var tipId = this.getUID(this.type)

      this.setContent()
      $tip.attr('id', tipId)
      this.$element.attr('aria-describedby', tipId)

      if (this.options.animation) $tip.addClass('fade')

      var placement = typeof this.options.placement == 'function' ?
        this.options.placement.call(this, $tip[0], this.$element[0]) :
        this.options.placement

      var autoToken = /\s?auto?\s?/i
      var autoPlace = autoToken.test(placement)
      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'

      $tip
        .detach()
        .css({ top: 0, left: 0, display: 'block' })
        .addClass(placement)
        .data('bs.' + this.type, this)

      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
      this.$element.trigger('inserted.bs.' + this.type)

      var pos          = this.getPosition()
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight

      if (autoPlace) {
        var orgPlacement = placement
        var viewportDim = this.getPosition(this.$viewport)

        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
                    placement

        $tip
          .removeClass(orgPlacement)
          .addClass(placement)
      }

      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)

      this.applyPlacement(calculatedOffset, placement)

      var complete = function () {
        var prevHoverState = that.hoverState
        that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

      $.support.transition && this.$tip.hasClass('fade') ?
        $tip
          .one('bsTransitionEnd', complete)
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
        complete()
    }
  }

  Tooltip.prototype.applyPlacement = function (offset, placement) {
    var $tip   = this.tip()
    var width  = $tip[0].offsetWidth
    var height = $tip[0].offsetHeight

    // manually read margins because getBoundingClientRect includes difference
    var marginTop = parseInt($tip.css('margin-top'), 10)
    var marginLeft = parseInt($tip.css('margin-left'), 10)

    // we must check for NaN for ie 8/9
    if (isNaN(marginTop))  marginTop  = 0
    if (isNaN(marginLeft)) marginLeft = 0

    offset.top  += marginTop
    offset.left += marginLeft

    // $.fn.offset doesn't round pixel values
    // so we use setOffset directly with our own function B-0
    $.offset.setOffset($tip[0], $.extend({
      using: function (props) {
        $tip.css({
          top: Math.round(props.top),
          left: Math.round(props.left)
        })
      }
    }, offset), 0)

    $tip.addClass('in')

    // check to see if placing tip in new offset caused the tip to resize itself
    var actualWidth  = $tip[0].offsetWidth
    var actualHeight = $tip[0].offsetHeight

    if (placement == 'top' && actualHeight != height) {
      offset.top = offset.top + height - actualHeight
    }

    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)

    if (delta.left) offset.left += delta.left
    else offset.top += delta.top

    var isVertical          = /top|bottom/.test(placement)
    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'

    $tip.offset(offset)
    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
  }

  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
    this.arrow()
      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
      .css(isVertical ? 'top' : 'left', '')
  }

  Tooltip.prototype.setContent = function () {
    var $tip  = this.tip()
    var title = this.getTitle()

    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
    $tip.removeClass('fade in top bottom left right')
  }

  Tooltip.prototype.hide = function (callback) {
    var that = this
    var $tip = $(this.$tip)
    var e    = $.Event('hide.bs.' + this.type)

    function complete() {
      if (that.hoverState != 'in') $tip.detach()
      that.$element
        .removeAttr('aria-describedby')
        .trigger('hidden.bs.' + that.type)
      callback && callback()
    }

    this.$element.trigger(e)

    if (e.isDefaultPrevented()) return

    $tip.removeClass('in')

    $.support.transition && $tip.hasClass('fade') ?
      $tip
        .one('bsTransitionEnd', complete)
        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
      complete()

    this.hoverState = null

    return this
  }

  Tooltip.prototype.fixTitle = function () {
    var $e = this.$element
    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
    }
  }

  Tooltip.prototype.hasContent = function () {
    return this.getTitle()
  }

  Tooltip.prototype.getPosition = function ($element) {
    $element   = $element || this.$element

    var el     = $element[0]
    var isBody = el.tagName == 'BODY'

    var elRect    = el.getBoundingClientRect()
    if (elRect.width == null) {
      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
    }
    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null

    return $.extend({}, elRect, scroll, outerDims, elOffset)
  }

  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }

  }

  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
    var delta = { top: 0, left: 0 }
    if (!this.$viewport) return delta

    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
    var viewportDimensions = this.getPosition(this.$viewport)

    if (/right|left/.test(placement)) {
      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
      if (topEdgeOffset < viewportDimensions.top) { // top overflow
        delta.top = viewportDimensions.top - topEdgeOffset
      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
      }
    } else {
      var leftEdgeOffset  = pos.left - viewportPadding
      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
        delta.left = viewportDimensions.left - leftEdgeOffset
      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
      }
    }

    return delta
  }

  Tooltip.prototype.getTitle = function () {
    var title
    var $e = this.$element
    var o  = this.options

    title = $e.attr('data-original-title')
      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)

    return title
  }

  Tooltip.prototype.getUID = function (prefix) {
    do prefix += ~~(Math.random() * 1000000)
    while (document.getElementById(prefix))
    return prefix
  }

  Tooltip.prototype.tip = function () {
    if (!this.$tip) {
      this.$tip = $(this.options.template)
      if (this.$tip.length != 1) {
        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
      }
    }
    return this.$tip
  }

  Tooltip.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
  }

  Tooltip.prototype.enable = function () {
    this.enabled = true
  }

  Tooltip.prototype.disable = function () {
    this.enabled = false
  }

  Tooltip.prototype.toggleEnabled = function () {
    this.enabled = !this.enabled
  }

  Tooltip.prototype.toggle = function (e) {
    var self = this
    if (e) {
      self = $(e.currentTarget).data('bs.' + this.type)
      if (!self) {
        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
        $(e.currentTarget).data('bs.' + this.type, self)
      }
    }

    if (e) {
      self.inState.click = !self.inState.click
      if (self.isInStateTrue()) self.enter(self)
      else self.leave(self)
    } else {
      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
    }
  }

  Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
    })
  }


  // TOOLTIP PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.tooltip')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tooltip

  $.fn.tooltip             = Plugin
  $.fn.tooltip.Constructor = Tooltip


  // TOOLTIP NO CONFLICT
  // ===================

  $.fn.tooltip.noConflict = function () {
    $.fn.tooltip = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: popover.js v3.3.6
 * http://getbootstrap.com/javascript/#popovers
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // POPOVER PUBLIC CLASS DEFINITION
  // ===============================

  var Popover = function (element, options) {
    this.init('popover', element, options)
  }

  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')

  Popover.VERSION  = '3.3.6'

  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
    placement: 'right',
    trigger: 'click',
    content: '',
    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
  })


  // NOTE: POPOVER EXTENDS tooltip.js
  // ================================

  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)

  Popover.prototype.constructor = Popover

  Popover.prototype.getDefaults = function () {
    return Popover.DEFAULTS
  }

  Popover.prototype.setContent = function () {
    var $tip    = this.tip()
    var title   = this.getTitle()
    var content = this.getContent()

    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
    ](content)

    $tip.removeClass('fade top bottom left right in')

    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
    // this manually by checking the contents.
    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
  }

  Popover.prototype.hasContent = function () {
    return this.getTitle() || this.getContent()
  }

  Popover.prototype.getContent = function () {
    var $e = this.$element
    var o  = this.options

    return $e.attr('data-content')
      || (typeof o.content == 'function' ?
            o.content.call($e[0]) :
            o.content)
  }

  Popover.prototype.arrow = function () {
    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
  }


  // POPOVER PLUGIN DEFINITION
  // =========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.popover')
      var options = typeof option == 'object' && option

      if (!data && /destroy|hide/.test(option)) return
      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.popover

  $.fn.popover             = Plugin
  $.fn.popover.Constructor = Popover


  // POPOVER NO CONFLICT
  // ===================

  $.fn.popover.noConflict = function () {
    $.fn.popover = old
    return this
  }

}(jQuery);

/* ========================================================================
 * Bootstrap: scrollspy.js v3.3.6
 * http://getbootstrap.com/javascript/#scrollspy
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // SCROLLSPY CLASS DEFINITION
  // ==========================

  function ScrollSpy(element, options) {
    this.$body          = $(document.body)
    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
    this.selector       = (this.options.target || '') + ' .nav li > a'
    this.offsets        = []
    this.targets        = []
    this.activeTarget   = null
    this.scrollHeight   = 0

    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
    this.refresh()
    this.process()
  }

  ScrollSpy.VERSION  = '3.3.6'

  ScrollSpy.DEFAULTS = {
    offset: 10
  }

  ScrollSpy.prototype.getScrollHeight = function () {
    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
  }

  ScrollSpy.prototype.refresh = function () {
    var that          = this
    var offsetMethod  = 'offset'
    var offsetBase    = 0

    this.offsets      = []
    this.targets      = []
    this.scrollHeight = this.getScrollHeight()

    if (!$.isWindow(this.$scrollElement[0])) {
      offsetMethod = 'position'
      offsetBase   = this.$scrollElement.scrollTop()
    }

    this.$body
      .find(this.selector)
      .map(function () {
        var $el   = $(this)
        var href  = $el.data('target') || $el.attr('href')
        var $href = /^#./.test(href) && $(href)

        return ($href
          && $href.length
          && $href.is(':visible')
          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
      })
      .sort(function (a, b) { return a[0] - b[0] })
      .each(function () {
        that.offsets.push(this[0])
        that.targets.push(this[1])
      })
  }

  ScrollSpy.prototype.process = function () {
    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
    var scrollHeight = this.getScrollHeight()
    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
    var offsets      = this.offsets
    var targets      = this.targets
    var activeTarget = this.activeTarget
    var i

    if (this.scrollHeight != scrollHeight) {
      this.refresh()
    }

    if (scrollTop >= maxScroll) {
      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
    }

    if (activeTarget && scrollTop < offsets[0]) {
      this.activeTarget = null
      return this.clear()
    }

    for (i = offsets.length; i--;) {
      activeTarget != targets[i]
        && scrollTop >= offsets[i]
        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
        && this.activate(targets[i])
    }
  }

  ScrollSpy.prototype.activate = function (target) {
    this.activeTarget = target

    this.clear()

    var selector = this.selector +
      '[data-target="' + target + '"],' +
      this.selector + '[href="' + target + '"]'

    var active = $(selector)
      .parents('li')
      .addClass('active')

    if (active.parent('.dropdown-menu').length) {
      active = active
        .closest('li.dropdown')
        .addClass('active')
    }

    active.trigger('activate.bs.scrollspy')
  }

  ScrollSpy.prototype.clear = function () {
    $(this.selector)
      .parentsUntil(this.options.target, '.active')
      .removeClass('active')
  }


  // SCROLLSPY PLUGIN DEFINITION
  // ===========================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.scrollspy')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.scrollspy

  $.fn.scrollspy             = Plugin
  $.fn.scrollspy.Constructor = ScrollSpy


  // SCROLLSPY NO CONFLICT
  // =====================

  $.fn.scrollspy.noConflict = function () {
    $.fn.scrollspy = old
    return this
  }


  // SCROLLSPY DATA-API
  // ==================

  $(window).on('load.bs.scrollspy.data-api', function () {
    $('[data-spy="scroll"]').each(function () {
      var $spy = $(this)
      Plugin.call($spy, $spy.data())
    })
  })

}(jQuery);

/* ========================================================================
 * Bootstrap: tab.js v3.3.6
 * http://getbootstrap.com/javascript/#tabs
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // TAB CLASS DEFINITION
  // ====================

  var Tab = function (element) {
    // jscs:disable requireDollarBeforejQueryAssignment
    this.element = $(element)
    // jscs:enable requireDollarBeforejQueryAssignment
  }

  Tab.VERSION = '3.3.6'

  Tab.TRANSITION_DURATION = 150

  Tab.prototype.show = function () {
    var $this    = this.element
    var $ul      = $this.closest('ul:not(.dropdown-menu)')
    var selector = $this.data('target')

    if (!selector) {
      selector = $this.attr('href')
      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
    }

    if ($this.parent('li').hasClass('active')) return

    var $previous = $ul.find('.active:last a')
    var hideEvent = $.Event('hide.bs.tab', {
      relatedTarget: $this[0]
    })
    var showEvent = $.Event('show.bs.tab', {
      relatedTarget: $previous[0]
    })

    $previous.trigger(hideEvent)
    $this.trigger(showEvent)

    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return

    var $target = $(selector)

    this.activate($this.closest('li'), $ul)
    this.activate($target, $target.parent(), function () {
      $previous.trigger({
        type: 'hidden.bs.tab',
        relatedTarget: $this[0]
      })
      $this.trigger({
        type: 'shown.bs.tab',
        relatedTarget: $previous[0]
      })
    })
  }

  Tab.prototype.activate = function (element, container, callback) {
    var $active    = container.find('> .active')
    var transition = callback
      && $.support.transition
      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)

    function next() {
      $active
        .removeClass('active')
        .find('> .dropdown-menu > .active')
          .removeClass('active')
        .end()
        .find('[data-toggle="tab"]')
          .attr('aria-expanded', false)

      element
        .addClass('active')
        .find('[data-toggle="tab"]')
          .attr('aria-expanded', true)

      if (transition) {
        element[0].offsetWidth // reflow for transition
        element.addClass('in')
      } else {
        element.removeClass('fade')
      }

      if (element.parent('.dropdown-menu').length) {
        element
          .closest('li.dropdown')
            .addClass('active')
          .end()
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', true)
      }

      callback && callback()
    }

    $active.length && transition ?
      $active
        .one('bsTransitionEnd', next)
        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
      next()

    $active.removeClass('in')
  }


  // TAB PLUGIN DEFINITION
  // =====================

  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.tab')

      if (!data) $this.data('bs.tab', (data = new Tab(this)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.tab

  $.fn.tab             = Plugin
  $.fn.tab.Constructor = Tab


  // TAB NO CONFLICT
  // ===============

  $.fn.tab.noConflict = function () {
    $.fn.tab = old
    return this
  }


  // TAB DATA-API
  // ============

  var clickHandler = function (e) {
    e.preventDefault()
    Plugin.call($(this), 'show')
  }

  $(document)
    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)

}(jQuery);

/* ========================================================================
 * Bootstrap: affix.js v3.3.6
 * http://getbootstrap.com/javascript/#affix
 * ========================================================================
 * Copyright 2011-2015 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 * ======================================================================== */


+function ($) {
  'use strict';

  // AFFIX CLASS DEFINITION
  // ======================

  var Affix = function (element, options) {
    this.options = $.extend({}, Affix.DEFAULTS, options)

    this.$target = $(this.options.target)
      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))

    this.$element     = $(element)
    this.affixed      = null
    this.unpin        = null
    this.pinnedOffset = null

    this.checkPosition()
  }

  Affix.VERSION  = '3.3.6'

  Affix.RESET    = 'affix affix-top affix-bottom'

  Affix.DEFAULTS = {
    offset: 0,
    target: window
  }

  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
    var scrollTop    = this.$target.scrollTop()
    var position     = this.$element.offset()
    var targetHeight = this.$target.height()

    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false

    if (this.affixed == 'bottom') {
      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
    }

    var initializing   = this.affixed == null
    var colliderTop    = initializing ? scrollTop : position.top
    var colliderHeight = initializing ? targetHeight : height

    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'

    return false
  }

  Affix.prototype.getPinnedOffset = function () {
    if (this.pinnedOffset) return this.pinnedOffset
    this.$element.removeClass(Affix.RESET).addClass('affix')
    var scrollTop = this.$target.scrollTop()
    var position  = this.$element.offset()
    return (this.pinnedOffset = position.top - scrollTop)
  }

  Affix.prototype.checkPositionWithEventLoop = function () {
    setTimeout($.proxy(this.checkPosition, this), 1)
  }

  Affix.prototype.checkPosition = function () {
    if (!this.$element.is(':visible')) return

    var height       = this.$element.height()
    var offset       = this.options.offset
    var offsetTop    = offset.top
    var offsetBottom = offset.bottom
    var scrollHeight = Math.max($(document).height(), $(document.body).height())

    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)

    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)

    if (this.affixed != affix) {
      if (this.unpin != null) this.$element.css('top', '')

      var affixType = 'affix' + (affix ? '-' + affix : '')
      var e         = $.Event(affixType + '.bs.affix')

      this.$element.trigger(e)

      if (e.isDefaultPrevented()) return

      this.affixed = affix
      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null

      this.$element
        .removeClass(Affix.RESET)
        .addClass(affixType)
        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
    }

    if (affix == 'bottom') {
      this.$element.offset({
        top: scrollHeight - height - offsetBottom
      })
    }
  }


  // AFFIX PLUGIN DEFINITION
  // =======================

  function Plugin(option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.affix')
      var options = typeof option == 'object' && option

      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
      if (typeof option == 'string') data[option]()
    })
  }

  var old = $.fn.affix

  $.fn.affix             = Plugin
  $.fn.affix.Constructor = Affix


  // AFFIX NO CONFLICT
  // =================

  $.fn.affix.noConflict = function () {
    $.fn.affix = old
    return this
  }


  // AFFIX DATA-API
  // ==============

  $(window).on('load', function () {
    $('[data-spy="affix"]').each(function () {
      var $spy = $(this)
      var data = $spy.data()

      data.offset = data.offset || {}

      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
      if (data.offsetTop    != null) data.offset.top    = data.offsetTop

      Plugin.call($spy, data)
    })
  })

}(jQuery);

},{}],186:[function(require,module,exports){


//
// Generated on Tue Dec 16 2014 12:13:47 GMT+0100 (CET) by Charlie Robbins, Paolo Fragomeni & the Contributors (Using Codesurgeon).
// Version 1.2.6
//

(function (exports) {

/*
 * browser.js: Browser specific functionality for director.
 *
 * (C) 2011, Charlie Robbins, Paolo Fragomeni, & the Contributors.
 * MIT LICENSE
 *
 */

var dloc = document.location;

function dlocHashEmpty() {
  // Non-IE browsers return '' when the address bar shows '#'; Director's logic
  // assumes both mean empty.
  return dloc.hash === '' || dloc.hash === '#';
}

var listener = {
  mode: 'modern',
  hash: dloc.hash,
  history: false,

  check: function () {
    var h = dloc.hash;
    if (h != this.hash) {
      this.hash = h;
      this.onHashChanged();
    }
  },

  fire: function () {
    if (this.mode === 'modern') {
      this.history === true ? window.onpopstate() : window.onhashchange();
    }
    else {
      this.onHashChanged();
    }
  },

  init: function (fn, history) {
    var self = this;
    this.history = history;

    if (!Router.listeners) {
      Router.listeners = [];
    }

    function onchange(onChangeEvent) {
      for (var i = 0, l = Router.listeners.length; i < l; i++) {
        Router.listeners[i](onChangeEvent);
      }
    }

    //note IE8 is being counted as 'modern' because it has the hashchange event
    if ('onhashchange' in window && (document.documentMode === undefined
      || document.documentMode > 7)) {
      // At least for now HTML5 history is available for 'modern' browsers only
      if (this.history === true) {
        // There is an old bug in Chrome that causes onpopstate to fire even
        // upon initial page load. Since the handler is run manually in init(),
        // this would cause Chrome to run it twise. Currently the only
        // workaround seems to be to set the handler after the initial page load
        // http://code.google.com/p/chromium/issues/detail?id=63040
        setTimeout(function() {
          window.onpopstate = onchange;
        }, 500);
      }
      else {
        window.onhashchange = onchange;
      }
      this.mode = 'modern';
    }
    else {
      //
      // IE support, based on a concept by Erik Arvidson ...
      //
      var frame = document.createElement('iframe');
      frame.id = 'state-frame';
      frame.style.display = 'none';
      document.body.appendChild(frame);
      this.writeFrame('');

      if ('onpropertychange' in document && 'attachEvent' in document) {
        document.attachEvent('onpropertychange', function () {
          if (event.propertyName === 'location') {
            self.check();
          }
        });
      }

      window.setInterval(function () { self.check(); }, 50);

      this.onHashChanged = onchange;
      this.mode = 'legacy';
    }

    Router.listeners.push(fn);

    return this.mode;
  },

  destroy: function (fn) {
    if (!Router || !Router.listeners) {
      return;
    }

    var listeners = Router.listeners;

    for (var i = listeners.length - 1; i >= 0; i--) {
      if (listeners[i] === fn) {
        listeners.splice(i, 1);
      }
    }
  },

  setHash: function (s) {
    // Mozilla always adds an entry to the history
    if (this.mode === 'legacy') {
      this.writeFrame(s);
    }

    if (this.history === true) {
      window.history.pushState({}, document.title, s);
      // Fire an onpopstate event manually since pushing does not obviously
      // trigger the pop event.
      this.fire();
    } else {
      dloc.hash = (s[0] === '/') ? s : '/' + s;
    }
    return this;
  },

  writeFrame: function (s) {
    // IE support...
    var f = document.getElementById('state-frame');
    var d = f.contentDocument || f.contentWindow.document;
    d.open();
    d.write("<script>_hash = '" + s + "'; onload = parent.listener.syncHash;<script>");
    d.close();
  },

  syncHash: function () {
    // IE support...
    var s = this._hash;
    if (s != dloc.hash) {
      dloc.hash = s;
    }
    return this;
  },

  onHashChanged: function () {}
};

var Router = exports.Router = function (routes) {
  if (!(this instanceof Router)) return new Router(routes);

  this.params   = {};
  this.routes   = {};
  this.methods  = ['on', 'once', 'after', 'before'];
  this.scope    = [];
  this._methods = {};

  this._insert = this.insert;
  this.insert = this.insertEx;

  this.historySupport = (window.history != null ? window.history.pushState : null) != null

  this.configure();
  this.mount(routes || {});
};

Router.prototype.init = function (r) {
  var self = this
    , routeTo;
  this.handler = function(onChangeEvent) {
    var newURL = onChangeEvent && onChangeEvent.newURL || window.location.hash;
    var url = self.history === true ? self.getPath() : newURL.replace(/.*#/, '');
    self.dispatch('on', url.charAt(0) === '/' ? url : '/' + url);
  };

  listener.init(this.handler, this.history);

  if (this.history === false) {
    if (dlocHashEmpty() && r) {
      dloc.hash = r;
    } else if (!dlocHashEmpty()) {
      self.dispatch('on', '/' + dloc.hash.replace(/^(#\/|#|\/)/, ''));
    }
  }
  else {
    if (this.convert_hash_in_init) {
      // Use hash as route
      routeTo = dlocHashEmpty() && r ? r : !dlocHashEmpty() ? dloc.hash.replace(/^#/, '') : null;
      if (routeTo) {
        window.history.replaceState({}, document.title, routeTo);
      }
    }
    else {
      // Use canonical url
      routeTo = this.getPath();
    }

    // Router has been initialized, but due to the chrome bug it will not
    // yet actually route HTML5 history state changes. Thus, decide if should route.
    if (routeTo || this.run_in_init === true) {
      this.handler();
    }
  }

  return this;
};

Router.prototype.explode = function () {
  var v = this.history === true ? this.getPath() : dloc.hash;
  if (v.charAt(1) === '/') { v=v.slice(1) }
  return v.slice(1, v.length).split("/");
};

Router.prototype.setRoute = function (i, v, val) {
  var url = this.explode();

  if (typeof i === 'number' && typeof v === 'string') {
    url[i] = v;
  }
  else if (typeof val === 'string') {
    url.splice(i, v, s);
  }
  else {
    url = [i];
  }

  listener.setHash(url.join('/'));
  return url;
};

//
// ### function insertEx(method, path, route, parent)
// #### @method {string} Method to insert the specific `route`.
// #### @path {Array} Parsed path to insert the `route` at.
// #### @route {Array|function} Route handlers to insert.
// #### @parent {Object} **Optional** Parent "routes" to insert into.
// insert a callback that will only occur once per the matched route.
//
Router.prototype.insertEx = function(method, path, route, parent) {
  if (method === "once") {
    method = "on";
    route = function(route) {
      var once = false;
      return function() {
        if (once) return;
        once = true;
        return route.apply(this, arguments);
      };
    }(route);
  }
  return this._insert(method, path, route, parent);
};

Router.prototype.getRoute = function (v) {
  var ret = v;

  if (typeof v === "number") {
    ret = this.explode()[v];
  }
  else if (typeof v === "string"){
    var h = this.explode();
    ret = h.indexOf(v);
  }
  else {
    ret = this.explode();
  }

  return ret;
};

Router.prototype.destroy = function () {
  listener.destroy(this.handler);
  return this;
};

Router.prototype.getPath = function () {
  var path = window.location.pathname;
  if (path.substr(0, 1) !== '/') {
    path = '/' + path;
  }
  return path;
};
function _every(arr, iterator) {
  for (var i = 0; i < arr.length; i += 1) {
    if (iterator(arr[i], i, arr) === false) {
      return;
    }
  }
}

function _flatten(arr) {
  var flat = [];
  for (var i = 0, n = arr.length; i < n; i++) {
    flat = flat.concat(arr[i]);
  }
  return flat;
}

function _asyncEverySeries(arr, iterator, callback) {
  if (!arr.length) {
    return callback();
  }
  var completed = 0;
  (function iterate() {
    iterator(arr[completed], function(err) {
      if (err || err === false) {
        callback(err);
        callback = function() {};
      } else {
        completed += 1;
        if (completed === arr.length) {
          callback();
        } else {
          iterate();
        }
      }
    });
  })();
}

function paramifyString(str, params, mod) {
  mod = str;
  for (var param in params) {
    if (params.hasOwnProperty(param)) {
      mod = params[param](str);
      if (mod !== str) {
        break;
      }
    }
  }
  return mod === str ? "([._a-zA-Z0-9-%()]+)" : mod;
}

function regifyString(str, params) {
  var matches, last = 0, out = "";
  while (matches = str.substr(last).match(/[^\w\d\- %@&]*\*[^\w\d\- %@&]*/)) {
    last = matches.index + matches[0].length;
    matches[0] = matches[0].replace(/^\*/, "([_.()!\\ %@&a-zA-Z0-9-]+)");
    out += str.substr(0, matches.index) + matches[0];
  }
  str = out += str.substr(last);
  var captures = str.match(/:([^\/]+)/ig), capture, length;
  if (captures) {
    length = captures.length;
    for (var i = 0; i < length; i++) {
      capture = captures[i];
      if (capture.slice(0, 2) === "::") {
        str = capture.slice(1);
      } else {
        str = str.replace(capture, paramifyString(capture, params));
      }
    }
  }
  return str;
}

function terminator(routes, delimiter, start, stop) {
  var last = 0, left = 0, right = 0, start = (start || "(").toString(), stop = (stop || ")").toString(), i;
  for (i = 0; i < routes.length; i++) {
    var chunk = routes[i];
    if (chunk.indexOf(start, last) > chunk.indexOf(stop, last) || ~chunk.indexOf(start, last) && !~chunk.indexOf(stop, last) || !~chunk.indexOf(start, last) && ~chunk.indexOf(stop, last)) {
      left = chunk.indexOf(start, last);
      right = chunk.indexOf(stop, last);
      if (~left && !~right || !~left && ~right) {
        var tmp = routes.slice(0, (i || 1) + 1).join(delimiter);
        routes = [ tmp ].concat(routes.slice((i || 1) + 1));
      }
      last = (right > left ? right : left) + 1;
      i = 0;
    } else {
      last = 0;
    }
  }
  return routes;
}

var QUERY_SEPARATOR = /\?.*/;

Router.prototype.configure = function(options) {
  options = options || {};
  for (var i = 0; i < this.methods.length; i++) {
    this._methods[this.methods[i]] = true;
  }
  this.recurse = options.recurse || this.recurse || false;
  this.async = options.async || false;
  this.delimiter = options.delimiter || "/";
  this.strict = typeof options.strict === "undefined" ? true : options.strict;
  this.notfound = options.notfound;
  this.resource = options.resource;
  this.history = options.html5history && this.historySupport || false;
  this.run_in_init = this.history === true && options.run_handler_in_init !== false;
  this.convert_hash_in_init = this.history === true && options.convert_hash_in_init !== false;
  this.every = {
    after: options.after || null,
    before: options.before || null,
    on: options.on || null
  };
  return this;
};

Router.prototype.param = function(token, matcher) {
  if (token[0] !== ":") {
    token = ":" + token;
  }
  var compiled = new RegExp(token, "g");
  this.params[token] = function(str) {
    return str.replace(compiled, matcher.source || matcher);
  };
  return this;
};

Router.prototype.on = Router.prototype.route = function(method, path, route) {
  var self = this;
  if (!route && typeof path == "function") {
    route = path;
    path = method;
    method = "on";
  }
  if (Array.isArray(path)) {
    return path.forEach(function(p) {
      self.on(method, p, route);
    });
  }
  if (path.source) {
    path = path.source.replace(/\\\//ig, "/");
  }
  if (Array.isArray(method)) {
    return method.forEach(function(m) {
      self.on(m.toLowerCase(), path, route);
    });
  }
  path = path.split(new RegExp(this.delimiter));
  path = terminator(path, this.delimiter);
  this.insert(method, this.scope.concat(path), route);
};

Router.prototype.path = function(path, routesFn) {
  var self = this, length = this.scope.length;
  if (path.source) {
    path = path.source.replace(/\\\//ig, "/");
  }
  path = path.split(new RegExp(this.delimiter));
  path = terminator(path, this.delimiter);
  this.scope = this.scope.concat(path);
  routesFn.call(this, this);
  this.scope.splice(length, path.length);
};

Router.prototype.dispatch = function(method, path, callback) {
  var self = this, fns = this.traverse(method, path.replace(QUERY_SEPARATOR, ""), this.routes, ""), invoked = this._invoked, after;
  this._invoked = true;
  if (!fns || fns.length === 0) {
    this.last = [];
    if (typeof this.notfound === "function") {
      this.invoke([ this.notfound ], {
        method: method,
        path: path
      }, callback);
    }
    return false;
  }
  if (this.recurse === "forward") {
    fns = fns.reverse();
  }
  function updateAndInvoke() {
    self.last = fns.after;
    self.invoke(self.runlist(fns), self, callback);
  }
  after = this.every && this.every.after ? [ this.every.after ].concat(this.last) : [ this.last ];
  if (after && after.length > 0 && invoked) {
    if (this.async) {
      this.invoke(after, this, updateAndInvoke);
    } else {
      this.invoke(after, this);
      updateAndInvoke();
    }
    return true;
  }
  updateAndInvoke();
  return true;
};

Router.prototype.invoke = function(fns, thisArg, callback) {
  var self = this;
  var apply;
  if (this.async) {
    apply = function(fn, next) {
      if (Array.isArray(fn)) {
        return _asyncEverySeries(fn, apply, next);
      } else if (typeof fn == "function") {
        fn.apply(thisArg, (fns.captures || []).concat(next));
      }
    };
    _asyncEverySeries(fns, apply, function() {
      if (callback) {
        callback.apply(thisArg, arguments);
      }
    });
  } else {
    apply = function(fn) {
      if (Array.isArray(fn)) {
        return _every(fn, apply);
      } else if (typeof fn === "function") {
        return fn.apply(thisArg, fns.captures || []);
      } else if (typeof fn === "string" && self.resource) {
        self.resource[fn].apply(thisArg, fns.captures || []);
      }
    };
    _every(fns, apply);
  }
};

Router.prototype.traverse = function(method, path, routes, regexp, filter) {
  var fns = [], current, exact, match, next, that;
  function filterRoutes(routes) {
    if (!filter) {
      return routes;
    }
    function deepCopy(source) {
      var result = [];
      for (var i = 0; i < source.length; i++) {
        result[i] = Array.isArray(source[i]) ? deepCopy(source[i]) : source[i];
      }
      return result;
    }
    function applyFilter(fns) {
      for (var i = fns.length - 1; i >= 0; i--) {
        if (Array.isArray(fns[i])) {
          applyFilter(fns[i]);
          if (fns[i].length === 0) {
            fns.splice(i, 1);
          }
        } else {
          if (!filter(fns[i])) {
            fns.splice(i, 1);
          }
        }
      }
    }
    var newRoutes = deepCopy(routes);
    newRoutes.matched = routes.matched;
    newRoutes.captures = routes.captures;
    newRoutes.after = routes.after.filter(filter);
    applyFilter(newRoutes);
    return newRoutes;
  }
  if (path === this.delimiter && routes[method]) {
    next = [ [ routes.before, routes[method] ].filter(Boolean) ];
    next.after = [ routes.after ].filter(Boolean);
    next.matched = true;
    next.captures = [];
    return filterRoutes(next);
  }
  for (var r in routes) {
    if (routes.hasOwnProperty(r) && (!this._methods[r] || this._methods[r] && typeof routes[r] === "object" && !Array.isArray(routes[r]))) {
      current = exact = regexp + this.delimiter + r;
      if (!this.strict) {
        exact += "[" + this.delimiter + "]?";
      }
      match = path.match(new RegExp("^" + exact));
      if (!match) {
        continue;
      }
      if (match[0] && match[0] == path && routes[r][method]) {
        next = [ [ routes[r].before, routes[r][method] ].filter(Boolean) ];
        next.after = [ routes[r].after ].filter(Boolean);
        next.matched = true;
        next.captures = match.slice(1);
        if (this.recurse && routes === this.routes) {
          next.push([ routes.before, routes.on ].filter(Boolean));
          next.after = next.after.concat([ routes.after ].filter(Boolean));
        }
        return filterRoutes(next);
      }
      next = this.traverse(method, path, routes[r], current);
      if (next.matched) {
        if (next.length > 0) {
          fns = fns.concat(next);
        }
        if (this.recurse) {
          fns.push([ routes[r].before, routes[r].on ].filter(Boolean));
          next.after = next.after.concat([ routes[r].after ].filter(Boolean));
          if (routes === this.routes) {
            fns.push([ routes["before"], routes["on"] ].filter(Boolean));
            next.after = next.after.concat([ routes["after"] ].filter(Boolean));
          }
        }
        fns.matched = true;
        fns.captures = next.captures;
        fns.after = next.after;
        return filterRoutes(fns);
      }
    }
  }
  return false;
};

Router.prototype.insert = function(method, path, route, parent) {
  var methodType, parentType, isArray, nested, part;
  path = path.filter(function(p) {
    return p && p.length > 0;
  });
  parent = parent || this.routes;
  part = path.shift();
  if (/\:|\*/.test(part) && !/\\d|\\w/.test(part)) {
    part = regifyString(part, this.params);
  }
  if (path.length > 0) {
    parent[part] = parent[part] || {};
    return this.insert(method, path, route, parent[part]);
  }
  if (!part && !path.length && parent === this.routes) {
    methodType = typeof parent[method];
    switch (methodType) {
     case "function":
      parent[method] = [ parent[method], route ];
      return;
     case "object":
      parent[method].push(route);
      return;
     case "undefined":
      parent[method] = route;
      return;
    }
    return;
  }
  parentType = typeof parent[part];
  isArray = Array.isArray(parent[part]);
  if (parent[part] && !isArray && parentType == "object") {
    methodType = typeof parent[part][method];
    switch (methodType) {
     case "function":
      parent[part][method] = [ parent[part][method], route ];
      return;
     case "object":
      parent[part][method].push(route);
      return;
     case "undefined":
      parent[part][method] = route;
      return;
    }
  } else if (parentType == "undefined") {
    nested = {};
    nested[method] = route;
    parent[part] = nested;
    return;
  }
  throw new Error("Invalid route context: " + parentType);
};



Router.prototype.extend = function(methods) {
  var self = this, len = methods.length, i;
  function extend(method) {
    self._methods[method] = true;
    self[method] = function() {
      var extra = arguments.length === 1 ? [ method, "" ] : [ method ];
      self.on.apply(self, extra.concat(Array.prototype.slice.call(arguments)));
    };
  }
  for (i = 0; i < len; i++) {
    extend(methods[i]);
  }
};

Router.prototype.runlist = function(fns) {
  var runlist = this.every && this.every.before ? [ this.every.before ].concat(_flatten(fns)) : _flatten(fns);
  if (this.every && this.every.on) {
    runlist.push(this.every.on);
  }
  runlist.captures = fns.captures;
  runlist.source = fns.source;
  return runlist;
};

Router.prototype.mount = function(routes, path) {
  if (!routes || typeof routes !== "object" || Array.isArray(routes)) {
    return;
  }
  var self = this;
  path = path || [];
  if (!Array.isArray(path)) {
    path = path.split(self.delimiter);
  }
  function insertOrMount(route, local) {
    var rename = route, parts = route.split(self.delimiter), routeType = typeof routes[route], isRoute = parts[0] === "" || !self._methods[parts[0]], event = isRoute ? "on" : rename;
    if (isRoute) {
      rename = rename.slice((rename.match(new RegExp("^" + self.delimiter)) || [ "" ])[0].length);
      parts.shift();
    }
    if (isRoute && routeType === "object" && !Array.isArray(routes[route])) {
      local = local.concat(parts);
      self.mount(routes[route], local);
      return;
    }
    if (isRoute) {
      local = local.concat(rename.split(self.delimiter));
      local = terminator(local, self.delimiter);
    }
    self.insert(event, local, routes[route]);
  }
  for (var route in routes) {
    if (routes.hasOwnProperty(route)) {
      insertOrMount(route, path.slice(0));
    }
  }
};



}(typeof exports === "object" ? exports : window));
},{}],187:[function(require,module,exports){
/**
 * Intro.js v2.1.0
 * https://github.com/usablica/intro.js
 * MIT licensed
 *
 * Copyright (C) 2013 usabli.ca - A weekend project by Afshin Mehrabani (@afshinmeh)
 */

(function (root, factory) {
  if (typeof exports === 'object') {
    // CommonJS
    factory(exports);
  } else if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['exports'], factory);
  } else {
    // Browser globals
    factory(root);
  }
} (this, function (exports) {
  //Default config/variables
  var VERSION = '2.1.0';

  /**
   * IntroJs main class
   *
   * @class IntroJs
   */
  function IntroJs(obj) {
    this._targetElement = obj;
    this._introItems = [];

    this._options = {
      /* Next button label in tooltip box */
      nextLabel: 'Next &rarr;',
      /* Previous button label in tooltip box */
      prevLabel: '&larr; Back',
      /* Skip button label in tooltip box */
      skipLabel: 'Skip',
      /* Done button label in tooltip box */
      doneLabel: 'Done',
      /* Default tooltip box position */
      tooltipPosition: 'bottom',
      /* Next CSS class for tooltip boxes */
      tooltipClass: '',
      /* CSS class that is added to the helperLayer */
      highlightClass: '',
      /* Close introduction when pressing Escape button? */
      exitOnEsc: true,
      /* Close introduction when clicking on overlay layer? */
      exitOnOverlayClick: true,
      /* Show step numbers in introduction? */
      showStepNumbers: true,
      /* Let user use keyboard to navigate the tour? */
      keyboardNavigation: true,
      /* Show tour control buttons? */
      showButtons: true,
      /* Show tour bullets? */
      showBullets: true,
      /* Show tour progress? */
      showProgress: false,
      /* Scroll to highlighted element? */
      scrollToElement: true,
      /* Set the overlay opacity */
      overlayOpacity: 0.8,
      /* Precedence of positions, when auto is enabled */
      positionPrecedence: ["bottom", "top", "right", "left"],
      /* Disable an interaction with element? */
      disableInteraction: false,
      /* Default hint position */
      hintPosition: 'top-middle',
      /* Hint button label */
      hintButtonLabel: 'Got it'
    };
  }

  /**
   * Initiate a new introduction/guide from an element in the page
   *
   * @api private
   * @method _introForElement
   * @param {Object} targetElm
   * @returns {Boolean} Success or not?
   */
  function _introForElement(targetElm) {
    var introItems = [],
        self = this;

    if (this._options.steps) {
      //use steps passed programmatically
      for (var i = 0, stepsLength = this._options.steps.length; i < stepsLength; i++) {
        var currentItem = _cloneObject(this._options.steps[i]);
        //set the step
        currentItem.step = introItems.length + 1;
        //use querySelector function only when developer used CSS selector
        if (typeof(currentItem.element) === 'string') {
          //grab the element with given selector from the page
          currentItem.element = document.querySelector(currentItem.element);
        }

        //intro without element
        if (typeof(currentItem.element) === 'undefined' || currentItem.element == null) {
          var floatingElementQuery = document.querySelector(".introjsFloatingElement");

          if (floatingElementQuery == null) {
            floatingElementQuery = document.createElement('div');
            floatingElementQuery.className = 'introjsFloatingElement';

            document.body.appendChild(floatingElementQuery);
          }

          currentItem.element  = floatingElementQuery;
          currentItem.position = 'floating';
        }

        if (currentItem.element != null) {
          introItems.push(currentItem);
        }
      }

    } else {
      //use steps from data-* annotations
      var allIntroSteps = targetElm.querySelectorAll('*[data-intro]');
      //if there's no element to intro
      if (allIntroSteps.length < 1) {
        return false;
      }

      //first add intro items with data-step
      for (var i = 0, elmsLength = allIntroSteps.length; i < elmsLength; i++) {
        var currentElement = allIntroSteps[i];

        // skip hidden elements
        if (currentElement.style.display == 'none') {
          continue;
        }

        var step = parseInt(currentElement.getAttribute('data-step'), 10);

        if (step > 0) {
          introItems[step - 1] = {
            element: currentElement,
            intro: currentElement.getAttribute('data-intro'),
            step: parseInt(currentElement.getAttribute('data-step'), 10),
            tooltipClass: currentElement.getAttribute('data-tooltipClass'),
            highlightClass: currentElement.getAttribute('data-highlightClass'),
            position: currentElement.getAttribute('data-position') || this._options.tooltipPosition
          };
        }
      }

      //next add intro items without data-step
      //todo: we need a cleanup here, two loops are redundant
      var nextStep = 0;
      for (var i = 0, elmsLength = allIntroSteps.length; i < elmsLength; i++) {
        var currentElement = allIntroSteps[i];

        if (currentElement.getAttribute('data-step') == null) {

          while (true) {
            if (typeof introItems[nextStep] == 'undefined') {
              break;
            } else {
              nextStep++;
            }
          }

          introItems[nextStep] = {
            element: currentElement,
            intro: currentElement.getAttribute('data-intro'),
            step: nextStep + 1,
            tooltipClass: currentElement.getAttribute('data-tooltipClass'),
            highlightClass: currentElement.getAttribute('data-highlightClass'),
            position: currentElement.getAttribute('data-position') || this._options.tooltipPosition
          };
        }
      }
    }

    //removing undefined/null elements
    var tempIntroItems = [];
    for (var z = 0; z < introItems.length; z++) {
      introItems[z] && tempIntroItems.push(introItems[z]);  // copy non-empty values to the end of the array
    }

    introItems = tempIntroItems;

    //Ok, sort all items with given steps
    introItems.sort(function (a, b) {
      return a.step - b.step;
    });

    //set it to the introJs object
    self._introItems = introItems;

    //add overlay layer to the page
    if(_addOverlayLayer.call(self, targetElm)) {
      //then, start the show
      _nextStep.call(self);

      var skipButton     = targetElm.querySelector('.introjs-skipbutton'),
          nextStepButton = targetElm.querySelector('.introjs-nextbutton');

      self._onKeyDown = function(e) {
        if (e.keyCode === 27 && self._options.exitOnEsc == true) {
          //escape key pressed, exit the intro
          //check if exit callback is defined
          if (self._introExitCallback != undefined) {
            self._introExitCallback.call(self);
          }
          _exitIntro.call(self, targetElm);
        } else if(e.keyCode === 37) {
          //left arrow
          _previousStep.call(self);
        } else if (e.keyCode === 39) {
          //right arrow
          _nextStep.call(self);
        } else if (e.keyCode === 13) {
          //srcElement === ie
          var target = e.target || e.srcElement;
          if (target && target.className.indexOf('introjs-prevbutton') > 0) {
            //user hit enter while focusing on previous button
            _previousStep.call(self);
          } else if (target && target.className.indexOf('introjs-skipbutton') > 0) {
            //user hit enter while focusing on skip button
            if (self._introItems.length - 1 == self._currentStep && typeof (self._introCompleteCallback) === 'function') {
                self._introCompleteCallback.call(self);
            }
            //check if any callback is defined
            if (self._introExitCallback != undefined) {
              self._introExitCallback.call(self);
            }
            _exitIntro.call(self, targetElm);
          } else {
            //default behavior for responding to enter
            _nextStep.call(self);
          }

          //prevent default behaviour on hitting Enter, to prevent steps being skipped in some browsers
          if(e.preventDefault) {
            e.preventDefault();
          } else {
            e.returnValue = false;
          }
        }
      };

      self._onResize = function(e) {
        _setHelperLayerPosition.call(self, document.querySelector('.introjs-helperLayer'));
        _setHelperLayerPosition.call(self, document.querySelector('.introjs-tooltipReferenceLayer'));
      };

      if (window.addEventListener) {
        if (this._options.keyboardNavigation) {
          window.addEventListener('keydown', self._onKeyDown, true);
        }
        //for window resize
        window.addEventListener('resize', self._onResize, true);
      } else if (document.attachEvent) { //IE
        if (this._options.keyboardNavigation) {
          document.attachEvent('onkeydown', self._onKeyDown);
        }
        //for window resize
        document.attachEvent('onresize', self._onResize);
      }
    }
    return false;
  }

 /*
   * makes a copy of the object
   * @api private
   * @method _cloneObject
  */
  function _cloneObject(object) {
      if (object == null || typeof (object) != 'object' || typeof (object.nodeType) != 'undefined') {
        return object;
      }
      var temp = {};
      for (var key in object) {
        if (typeof (jQuery) != 'undefined' && object[key] instanceof jQuery) {
          temp[key] = object[key];
        } else {
          temp[key] = _cloneObject(object[key]);
        }
      }
      return temp;
  }
  /**
   * Go to specific step of introduction
   *
   * @api private
   * @method _goToStep
   */
  function _goToStep(step) {
    //because steps starts with zero
    this._currentStep = step - 2;
    if (typeof (this._introItems) !== 'undefined') {
      _nextStep.call(this);
    }
  }

  /**
   * Go to next step on intro
   *
   * @api private
   * @method _nextStep
   */
  function _nextStep() {
    this._direction = 'forward';

    if (typeof (this._currentStep) === 'undefined') {
      this._currentStep = 0;
    } else {
      ++this._currentStep;
    }

    if ((this._introItems.length) <= this._currentStep) {
      //end of the intro
      //check if any callback is defined
      if (typeof (this._introCompleteCallback) === 'function') {
        this._introCompleteCallback.call(this);
      }
      _exitIntro.call(this, this._targetElement);
      return;
    }

    var nextStep = this._introItems[this._currentStep];
    if (typeof (this._introBeforeChangeCallback) !== 'undefined') {
      this._introBeforeChangeCallback.call(this, nextStep.element);
    }

    _showElement.call(this, nextStep);
  }

  /**
   * Go to previous step on intro
   *
   * @api private
   * @method _nextStep
   */
  function _previousStep() {
    this._direction = 'backward';

    if (this._currentStep === 0) {
      return false;
    }

    var nextStep = this._introItems[--this._currentStep];
    if (typeof (this._introBeforeChangeCallback) !== 'undefined') {
      this._introBeforeChangeCallback.call(this, nextStep.element);
    }

    _showElement.call(this, nextStep);
  }

  /**
   * Exit from intro
   *
   * @api private
   * @method _exitIntro
   * @param {Object} targetElement
   */
  function _exitIntro(targetElement) {
    //remove overlay layer from the page
    var overlayLayer = targetElement.querySelector('.introjs-overlay');

    //return if intro already completed or skipped
    if (overlayLayer == null) {
      return;
    }

    //for fade-out animation
    overlayLayer.style.opacity = 0;
    setTimeout(function () {
      if (overlayLayer.parentNode) {
        overlayLayer.parentNode.removeChild(overlayLayer);
      }
    }, 500);

    //remove all helper layers
    var helperLayer = targetElement.querySelector('.introjs-helperLayer');
    if (helperLayer) {
      helperLayer.parentNode.removeChild(helperLayer);
    }

    var referenceLayer = targetElement.querySelector('.introjs-tooltipReferenceLayer');
    if (referenceLayer) {
      referenceLayer.parentNode.removeChild(referenceLayer);
    }
    //remove disableInteractionLayer
    var disableInteractionLayer = targetElement.querySelector('.introjs-disableInteraction');
    if (disableInteractionLayer) {
      disableInteractionLayer.parentNode.removeChild(disableInteractionLayer);
    }

    //remove intro floating element
    var floatingElement = document.querySelector('.introjsFloatingElement');
    if (floatingElement) {
      floatingElement.parentNode.removeChild(floatingElement);
    }

    //remove `introjs-showElement` class from the element
    var showElement = document.querySelector('.introjs-showElement');
    if (showElement) {
      showElement.className = showElement.className.replace(/introjs-[a-zA-Z]+/g, '').replace(/^\s+|\s+$/g, ''); // This is a manual trim.
    }

    //remove `introjs-fixParent` class from the elements
    var fixParents = document.querySelectorAll('.introjs-fixParent');
    if (fixParents && fixParents.length > 0) {
      for (var i = fixParents.length - 1; i >= 0; i--) {
        fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
      }
    }

    //clean listeners
    if (window.removeEventListener) {
      window.removeEventListener('keydown', this._onKeyDown, true);
    } else if (document.detachEvent) { //IE
      document.detachEvent('onkeydown', this._onKeyDown);
    }

    //set the step to zero
    this._currentStep = undefined;
  }

  /**
   * Render tooltip box in the page
   *
   * @api private
   * @method _placeTooltip
   * @param {HTMLElement} targetElement
   * @param {HTMLElement} tooltipLayer
   * @param {HTMLElement} arrowLayer
   * @param {HTMLElement} helperNumberLayer
   * @param {Boolean} hintMode
   */
  function _placeTooltip(targetElement, tooltipLayer, arrowLayer, helperNumberLayer, hintMode) {
    var tooltipCssClass = '',
        currentStepObj,
        tooltipOffset,
        targetOffset,
        windowSize,
        currentTooltipPosition;

    hintMode = hintMode || false;

    //reset the old style
    tooltipLayer.style.top        = null;
    tooltipLayer.style.right      = null;
    tooltipLayer.style.bottom     = null;
    tooltipLayer.style.left       = null;
    tooltipLayer.style.marginLeft = null;
    tooltipLayer.style.marginTop  = null;

    arrowLayer.style.display = 'inherit';

    if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
      helperNumberLayer.style.top  = null;
      helperNumberLayer.style.left = null;
    }

    //prevent error when `this._currentStep` is undefined
    if (!this._introItems[this._currentStep]) return;

    //if we have a custom css class for each step
    currentStepObj = this._introItems[this._currentStep];
    if (typeof (currentStepObj.tooltipClass) === 'string') {
      tooltipCssClass = currentStepObj.tooltipClass;
    } else {
      tooltipCssClass = this._options.tooltipClass;
    }

    tooltipLayer.className = ('introjs-tooltip ' + tooltipCssClass).replace(/^\s+|\s+$/g, '');

    currentTooltipPosition = this._introItems[this._currentStep].position;
    if ((currentTooltipPosition == "auto" || this._options.tooltipPosition == "auto")) {
      if (currentTooltipPosition != "floating") { // Floating is always valid, no point in calculating
        currentTooltipPosition = _determineAutoPosition.call(this, targetElement, tooltipLayer, currentTooltipPosition);
      }
    }
    targetOffset  = _getOffset(targetElement);
    tooltipOffset = _getOffset(tooltipLayer);
    windowSize    = _getWinSize();

    switch (currentTooltipPosition) {
      case 'top':
        arrowLayer.className = 'introjs-arrow bottom';

        if (hintMode) {
          var tooltipLayerStyleLeft = 0;
        } else {
          var tooltipLayerStyleLeft = 15;
        }

        _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
        tooltipLayer.style.bottom = (targetOffset.height +  20) + 'px';
        break;
      case 'right':
        tooltipLayer.style.left = (targetOffset.width + 20) + 'px';
        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
          // In this case, right would have fallen below the bottom of the screen.
          // Modify so that the bottom of the tooltip connects with the target
          arrowLayer.className = "introjs-arrow left-bottom";
          tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px";
        } else {
          arrowLayer.className = 'introjs-arrow left';
        }
        break;
      case 'left':
        if (!hintMode && this._options.showStepNumbers == true) {
          tooltipLayer.style.top = '15px';
        }

        if (targetOffset.top + tooltipOffset.height > windowSize.height) {
          // In this case, left would have fallen below the bottom of the screen.
          // Modify so that the bottom of the tooltip connects with the target
          tooltipLayer.style.top = "-" + (tooltipOffset.height - targetOffset.height - 20) + "px";
          arrowLayer.className = 'introjs-arrow right-bottom';
        } else {
          arrowLayer.className = 'introjs-arrow right';
        }
        tooltipLayer.style.right = (targetOffset.width + 20) + 'px';

        break;
      case 'floating':
        arrowLayer.style.display = 'none';

        //we have to adjust the top and left of layer manually for intro items without element
        tooltipLayer.style.left   = '50%';
        tooltipLayer.style.top    = '50%';
        tooltipLayer.style.marginLeft = '-' + (tooltipOffset.width / 2)  + 'px';
        tooltipLayer.style.marginTop  = '-' + (tooltipOffset.height / 2) + 'px';

        if (typeof(helperNumberLayer) != 'undefined' && helperNumberLayer != null) {
          helperNumberLayer.style.left = '-' + ((tooltipOffset.width / 2) + 18) + 'px';
          helperNumberLayer.style.top  = '-' + ((tooltipOffset.height / 2) + 18) + 'px';
        }

        break;
      case 'bottom-right-aligned':
        arrowLayer.className      = 'introjs-arrow top-right';

        var tooltipLayerStyleRight = 0;
        _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer);
        tooltipLayer.style.top    = (targetOffset.height +  20) + 'px';
        break;

      case 'bottom-middle-aligned':
        arrowLayer.className      = 'introjs-arrow top-middle';

        var tooltipLayerStyleLeftRight = targetOffset.width / 2 - tooltipOffset.width / 2;

        // a fix for middle aligned hints
        if (hintMode) {
          tooltipLayerStyleLeftRight += 5;
        }

        if (_checkLeft(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, tooltipLayer)) {
          tooltipLayer.style.right = null;
          _checkRight(targetOffset, tooltipLayerStyleLeftRight, tooltipOffset, windowSize, tooltipLayer);
        }
        tooltipLayer.style.top = (targetOffset.height + 20) + 'px';
        break;

      case 'bottom-left-aligned':
      // Bottom-left-aligned is the same as the default bottom
      case 'bottom':
      // Bottom going to follow the default behavior
      default:
        arrowLayer.className = 'introjs-arrow top';

        var tooltipLayerStyleLeft = 0;
        _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer);
        tooltipLayer.style.top    = (targetOffset.height +  20) + 'px';
        break;
    }
  }

  /**
   * Set tooltip left so it doesn't go off the right side of the window
   *
   * @return boolean true, if tooltipLayerStyleLeft is ok.  false, otherwise.
   */
  function _checkRight(targetOffset, tooltipLayerStyleLeft, tooltipOffset, windowSize, tooltipLayer) {
    if (targetOffset.left + tooltipLayerStyleLeft + tooltipOffset.width > windowSize.width) {
      // off the right side of the window
      tooltipLayer.style.left = (windowSize.width - tooltipOffset.width - targetOffset.left) + 'px';
      return false;
    }
    tooltipLayer.style.left = tooltipLayerStyleLeft + 'px';
    return true;
  }

  /**
   * Set tooltip right so it doesn't go off the left side of the window
   *
   * @return boolean true, if tooltipLayerStyleRight is ok.  false, otherwise.
   */
  function _checkLeft(targetOffset, tooltipLayerStyleRight, tooltipOffset, tooltipLayer) {
    if (targetOffset.left + targetOffset.width - tooltipLayerStyleRight - tooltipOffset.width < 0) {
      // off the left side of the window
      tooltipLayer.style.left = (-targetOffset.left) + 'px';
      return false;
    }
    tooltipLayer.style.right = tooltipLayerStyleRight + 'px';
    return true;
  }

  /**
   * Determines the position of the tooltip based on the position precedence and availability
   * of screen space.
   *
   * @param {Object} targetElement
   * @param {Object} tooltipLayer
   * @param {Object} desiredTooltipPosition
   *
   */
  function _determineAutoPosition(targetElement, tooltipLayer, desiredTooltipPosition) {

    // Take a clone of position precedence. These will be the available
    var possiblePositions = this._options.positionPrecedence.slice();

    var windowSize = _getWinSize();
    var tooltipHeight = _getOffset(tooltipLayer).height + 10;
    var tooltipWidth = _getOffset(tooltipLayer).width + 20;
    var targetOffset = _getOffset(targetElement);

    // If we check all the possible areas, and there are no valid places for the tooltip, the element
    // must take up most of the screen real estate. Show the tooltip floating in the middle of the screen.
    var calculatedPosition = "floating";

    // Check if the width of the tooltip + the starting point would spill off the right side of the screen
    // If no, neither bottom or top are valid
    if (targetOffset.left + tooltipWidth > windowSize.width || ((targetOffset.left + (targetOffset.width / 2)) - tooltipWidth) < 0) {
      _removeEntry(possiblePositions, "bottom");
      _removeEntry(possiblePositions, "top");
    } else {
      // Check for space below
      if ((targetOffset.height + targetOffset.top + tooltipHeight) > windowSize.height) {
        _removeEntry(possiblePositions, "bottom");
      }

      // Check for space above
      if (targetOffset.top - tooltipHeight < 0) {
        _removeEntry(possiblePositions, "top");
      }
    }

    // Check for space to the right
    if (targetOffset.width + targetOffset.left + tooltipWidth > windowSize.width) {
      _removeEntry(possiblePositions, "right");
    }

    // Check for space to the left
    if (targetOffset.left - tooltipWidth < 0) {
      _removeEntry(possiblePositions, "left");
    }

    // At this point, our array only has positions that are valid. Pick the first one, as it remains in order
    if (possiblePositions.length > 0) {
      calculatedPosition = possiblePositions[0];
    }

    // If the requested position is in the list, replace our calculated choice with that
    if (desiredTooltipPosition && desiredTooltipPosition != "auto") {
      if (possiblePositions.indexOf(desiredTooltipPosition) > -1) {
        calculatedPosition = desiredTooltipPosition;
      }
    }

    return calculatedPosition;
  }

  /**
   * Remove an entry from a string array if it's there, does nothing if it isn't there.
   *
   * @param {Array} stringArray
   * @param {String} stringToRemove
   */
  function _removeEntry(stringArray, stringToRemove) {
    if (stringArray.indexOf(stringToRemove) > -1) {
      stringArray.splice(stringArray.indexOf(stringToRemove), 1);
    }
  }

  /**
   * Update the position of the helper layer on the screen
   *
   * @api private
   * @method _setHelperLayerPosition
   * @param {Object} helperLayer
   */
  function _setHelperLayerPosition(helperLayer) {
    if (helperLayer) {
      //prevent error when `this._currentStep` in undefined
      if (!this._introItems[this._currentStep]) return;

      var currentElement  = this._introItems[this._currentStep],
          elementPosition = _getOffset(currentElement.element),
          widthHeightPadding = 10;

      // If the target element is fixed, the tooltip should be fixed as well.
      // Otherwise, remove a fixed class that may be left over from the previous
      // step.
      if (_isFixed(currentElement.element)) {
        helperLayer.className += ' introjs-fixedTooltip';
      } else {
        helperLayer.className = helperLayer.className.replace(' introjs-fixedTooltip', '');
      }

      if (currentElement.position == 'floating') {
        widthHeightPadding = 0;
      }

      //set new position to helper layer
      helperLayer.setAttribute('style', 'width: ' + (elementPosition.width  + widthHeightPadding)  + 'px; ' +
                                        'height:' + (elementPosition.height + widthHeightPadding)  + 'px; ' +
                                        'top:'    + (elementPosition.top    - 5)   + 'px;' +
                                        'left: '  + (elementPosition.left   - 5)   + 'px;');

    }
  }

  /**
   * Add disableinteraction layer and adjust the size and position of the layer
   *
   * @api private
   * @method _disableInteraction
   */
  function _disableInteraction() {
    var disableInteractionLayer = document.querySelector('.introjs-disableInteraction');
    if (disableInteractionLayer === null) {
      disableInteractionLayer = document.createElement('div');
      disableInteractionLayer.className = 'introjs-disableInteraction';
      this._targetElement.appendChild(disableInteractionLayer);
    }

    _setHelperLayerPosition.call(this, disableInteractionLayer);
  }

  /**
   * Setting anchors to behave like buttons
   *
   * @api private
   * @method _setAnchorAsButton
   */
  function _setAnchorAsButton(anchor){
    anchor.setAttribute('role', 'button');
    anchor.tabIndex = 0;
  }

  /**
   * Show an element on the page
   *
   * @api private
   * @method _showElement
   * @param {Object} targetElement
   */
  function _showElement(targetElement) {

    if (typeof (this._introChangeCallback) !== 'undefined') {
      this._introChangeCallback.call(this, targetElement.element);
    }

    var self = this,
        oldHelperLayer = document.querySelector('.introjs-helperLayer'),
        oldReferenceLayer = document.querySelector('.introjs-tooltipReferenceLayer'),
        highlightClass = 'introjs-helperLayer',
        elementPosition = _getOffset(targetElement.element);

    //check for a current step highlight class
    if (typeof (targetElement.highlightClass) === 'string') {
      highlightClass += (' ' + targetElement.highlightClass);
    }
    //check for options highlight class
    if (typeof (this._options.highlightClass) === 'string') {
      highlightClass += (' ' + this._options.highlightClass);
    }

    if (oldHelperLayer != null) {
      var oldHelperNumberLayer = oldReferenceLayer.querySelector('.introjs-helperNumberLayer'),
          oldtooltipLayer      = oldReferenceLayer.querySelector('.introjs-tooltiptext'),
          oldArrowLayer        = oldReferenceLayer.querySelector('.introjs-arrow'),
          oldtooltipContainer  = oldReferenceLayer.querySelector('.introjs-tooltip'),
          skipTooltipButton    = oldReferenceLayer.querySelector('.introjs-skipbutton'),
          prevTooltipButton    = oldReferenceLayer.querySelector('.introjs-prevbutton'),
          nextTooltipButton    = oldReferenceLayer.querySelector('.introjs-nextbutton');

      //update or reset the helper highlight class
      oldHelperLayer.className = highlightClass;
      //hide the tooltip
      oldtooltipContainer.style.opacity = 0;
      oldtooltipContainer.style.display = "none";

      if (oldHelperNumberLayer != null) {
        var lastIntroItem = this._introItems[(targetElement.step - 2 >= 0 ? targetElement.step - 2 : 0)];

        if (lastIntroItem != null && (this._direction == 'forward' && lastIntroItem.position == 'floating') || (this._direction == 'backward' && targetElement.position == 'floating')) {
          oldHelperNumberLayer.style.opacity = 0;
        }
      }

      //set new position to helper layer
      _setHelperLayerPosition.call(self, oldHelperLayer);
      _setHelperLayerPosition.call(self, oldReferenceLayer);

      //remove `introjs-fixParent` class from the elements
      var fixParents = document.querySelectorAll('.introjs-fixParent');
      if (fixParents && fixParents.length > 0) {
        for (var i = fixParents.length - 1; i >= 0; i--) {
          fixParents[i].className = fixParents[i].className.replace(/introjs-fixParent/g, '').replace(/^\s+|\s+$/g, '');
        };
      }

      //remove old classes if the element still exist
      var oldShowElement = document.querySelector('.introjs-showElement');
      if(oldShowElement) {
        oldShowElement.className = oldShowElement.className.replace(/introjs-[a-zA-Z]+/g, '').replace(/^\s+|\s+$/g, '');
      }

      //we should wait until the CSS3 transition is competed (it's 0.3 sec) to prevent incorrect `height` and `width` calculation
      if (self._lastShowElementTimer) {
        clearTimeout(self._lastShowElementTimer);
      }
      self._lastShowElementTimer = setTimeout(function() {
        //set current step to the label
        if (oldHelperNumberLayer != null) {
          oldHelperNumberLayer.innerHTML = targetElement.step;
        }
        //set current tooltip text
        oldtooltipLayer.innerHTML = targetElement.intro;
        //set the tooltip position
        oldtooltipContainer.style.display = "block";
        _placeTooltip.call(self, targetElement.element, oldtooltipContainer, oldArrowLayer, oldHelperNumberLayer);

        //change active bullet
        oldReferenceLayer.querySelector('.introjs-bullets li > a.active').className = '';
        oldReferenceLayer.querySelector('.introjs-bullets li > a[data-stepnumber="' + targetElement.step + '"]').className = 'active';

        oldReferenceLayer.querySelector('.introjs-progress .introjs-progressbar').setAttribute('style', 'width:' + _getProgress.call(self) + '%;');

        //show the tooltip
        oldtooltipContainer.style.opacity = 1;
        if (oldHelperNumberLayer) oldHelperNumberLayer.style.opacity = 1;

        //reset button focus
        if (nextTooltipButton.tabIndex === -1) {
          //tabindex of -1 means we are at the end of the tour - focus on skip / done
          skipTooltipButton.focus();
        } else {
          //still in the tour, focus on next
          nextTooltipButton.focus();
        }
      }, 350);

    } else {
      var helperLayer       = document.createElement('div'),
          referenceLayer    = document.createElement('div'),
          arrowLayer        = document.createElement('div'),
          tooltipLayer      = document.createElement('div'),
          tooltipTextLayer  = document.createElement('div'),
          bulletsLayer      = document.createElement('div'),
          progressLayer     = document.createElement('div'),
          buttonsLayer      = document.createElement('div');

      helperLayer.className = highlightClass;
      referenceLayer.className = 'introjs-tooltipReferenceLayer';

      //set new position to helper layer
      _setHelperLayerPosition.call(self, helperLayer);
      _setHelperLayerPosition.call(self, referenceLayer);

      //add helper layer to target element
      this._targetElement.appendChild(helperLayer);
      this._targetElement.appendChild(referenceLayer);

      arrowLayer.className = 'introjs-arrow';

      tooltipTextLayer.className = 'introjs-tooltiptext';
      tooltipTextLayer.innerHTML = targetElement.intro;

      bulletsLayer.className = 'introjs-bullets';

      if (this._options.showBullets === false) {
        bulletsLayer.style.display = 'none';
      }

      var ulContainer = document.createElement('ul');

      for (var i = 0, stepsLength = this._introItems.length; i < stepsLength; i++) {
        var innerLi    = document.createElement('li');
        var anchorLink = document.createElement('a');

        anchorLink.onclick = function() {
          self.goToStep(this.getAttribute('data-stepnumber'));
        };

        if (i === (targetElement.step-1)) anchorLink.className = 'active';

        _setAnchorAsButton(anchorLink);
        anchorLink.innerHTML = "&nbsp;";
        anchorLink.setAttribute('data-stepnumber', this._introItems[i].step);

        innerLi.appendChild(anchorLink);
        ulContainer.appendChild(innerLi);
      }

      bulletsLayer.appendChild(ulContainer);

      progressLayer.className = 'introjs-progress';

      if (this._options.showProgress === false) {
        progressLayer.style.display = 'none';
      }
      var progressBar = document.createElement('div');
      progressBar.className = 'introjs-progressbar';
      progressBar.setAttribute('style', 'width:' + _getProgress.call(this) + '%;');

      progressLayer.appendChild(progressBar);

      buttonsLayer.className = 'introjs-tooltipbuttons';
      if (this._options.showButtons === false) {
        buttonsLayer.style.display = 'none';
      }

      tooltipLayer.className = 'introjs-tooltip';
      tooltipLayer.appendChild(tooltipTextLayer);
      tooltipLayer.appendChild(bulletsLayer);
      tooltipLayer.appendChild(progressLayer);

      //add helper layer number
      if (this._options.showStepNumbers == true) {
        var helperNumberLayer = document.createElement('span');
        helperNumberLayer.className = 'introjs-helperNumberLayer';
        helperNumberLayer.innerHTML = targetElement.step;
        referenceLayer.appendChild(helperNumberLayer);
      }

      tooltipLayer.appendChild(arrowLayer);
      referenceLayer.appendChild(tooltipLayer);

      //next button
      var nextTooltipButton = document.createElement('a');

      nextTooltipButton.onclick = function() {
        if (self._introItems.length - 1 != self._currentStep) {
          _nextStep.call(self);
        }
      };

      _setAnchorAsButton(nextTooltipButton);
      nextTooltipButton.innerHTML = this._options.nextLabel;

      //previous button
      var prevTooltipButton = document.createElement('a');

      prevTooltipButton.onclick = function() {
        if (self._currentStep != 0) {
          _previousStep.call(self);
        }
      };

      _setAnchorAsButton(prevTooltipButton);
      prevTooltipButton.innerHTML = this._options.prevLabel;

      //skip button
      var skipTooltipButton = document.createElement('a');
      skipTooltipButton.className = 'introjs-button introjs-skipbutton';
      _setAnchorAsButton(skipTooltipButton);
      skipTooltipButton.innerHTML = this._options.skipLabel;

      skipTooltipButton.onclick = function() {
        if (self._introItems.length - 1 == self._currentStep && typeof (self._introCompleteCallback) === 'function') {
          self._introCompleteCallback.call(self);
        }

        if (self._introItems.length - 1 != self._currentStep && typeof (self._introExitCallback) === 'function') {
          self._introExitCallback.call(self);
        }

        _exitIntro.call(self, self._targetElement);
      };

      buttonsLayer.appendChild(skipTooltipButton);

      //in order to prevent displaying next/previous button always
      if (this._introItems.length > 1) {
        buttonsLayer.appendChild(prevTooltipButton);
        buttonsLayer.appendChild(nextTooltipButton);
      }

      tooltipLayer.appendChild(buttonsLayer);

      //set proper position
      _placeTooltip.call(self, targetElement.element, tooltipLayer, arrowLayer, helperNumberLayer);
    }

    //disable interaction
    if (this._options.disableInteraction === true) {
      _disableInteraction.call(self);
    }

    prevTooltipButton.removeAttribute('tabIndex');
    nextTooltipButton.removeAttribute('tabIndex');

    if (this._currentStep == 0 && this._introItems.length > 1) {
      prevTooltipButton.className = 'introjs-button introjs-prevbutton introjs-disabled';
      prevTooltipButton.tabIndex = '-1';
      nextTooltipButton.className = 'introjs-button introjs-nextbutton';
      skipTooltipButton.innerHTML = this._options.skipLabel;
    } else if (this._introItems.length - 1 == this._currentStep || this._introItems.length == 1) {
      skipTooltipButton.innerHTML = this._options.doneLabel;
      prevTooltipButton.className = 'introjs-button introjs-prevbutton';
      nextTooltipButton.className = 'introjs-button introjs-nextbutton introjs-disabled';
      nextTooltipButton.tabIndex = '-1';
    } else {
      prevTooltipButton.className = 'introjs-button introjs-prevbutton';
      nextTooltipButton.className = 'introjs-button introjs-nextbutton';
      skipTooltipButton.innerHTML = this._options.skipLabel;
    }

    //Set focus on "next" button, so that hitting Enter always moves you onto the next step
    nextTooltipButton.focus();

    //add target element position style
    targetElement.element.className += ' introjs-showElement';

    var currentElementPosition = _getPropValue(targetElement.element, 'position');
    if (currentElementPosition !== 'absolute' &&
        currentElementPosition !== 'relative' &&
        currentElementPosition !== 'fixed') {
      //change to new intro item
      targetElement.element.className += ' introjs-relativePosition';
    }

    var parentElm = targetElement.element.parentNode;
    while (parentElm != null) {
      if (parentElm.tagName.toLowerCase() === 'body') break;

      //fix The Stacking Contenxt problem.
      //More detail: https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context
      var zIndex = _getPropValue(parentElm, 'z-index');
      var opacity = parseFloat(_getPropValue(parentElm, 'opacity'));
      var transform = _getPropValue(parentElm, 'transform') || _getPropValue(parentElm, '-webkit-transform') || _getPropValue(parentElm, '-moz-transform') || _getPropValue(parentElm, '-ms-transform') || _getPropValue(parentElm, '-o-transform');
      if (/[0-9]+/.test(zIndex) || opacity < 1 || (transform !== 'none' && transform !== undefined)) {
        parentElm.className += ' introjs-fixParent';
      }

      parentElm = parentElm.parentNode;
    }

    if (!_elementInViewport(targetElement.element) && this._options.scrollToElement === true) {
      var rect = targetElement.element.getBoundingClientRect(),
        winHeight = _getWinSize().height,
        top = rect.bottom - (rect.bottom - rect.top),
        bottom = rect.bottom - winHeight;

      //Scroll up
      if (top < 0 || targetElement.element.clientHeight > winHeight) {
        window.scrollBy(0, top - 30); // 30px padding from edge to look nice

      //Scroll down
      } else {
        window.scrollBy(0, bottom + 100); // 70px + 30px padding from edge to look nice
      }
    }

    if (typeof (this._introAfterChangeCallback) !== 'undefined') {
      this._introAfterChangeCallback.call(this, targetElement.element);
    }
  }

  /**
   * Get an element CSS property on the page
   * Thanks to JavaScript Kit: http://www.javascriptkit.com/dhtmltutors/dhtmlcascade4.shtml
   *
   * @api private
   * @method _getPropValue
   * @param {Object} element
   * @param {String} propName
   * @returns Element's property value
   */
  function _getPropValue (element, propName) {
    var propValue = '';
    if (element.currentStyle) { //IE
      propValue = element.currentStyle[propName];
    } else if (document.defaultView && document.defaultView.getComputedStyle) { //Others
      propValue = document.defaultView.getComputedStyle(element, null).getPropertyValue(propName);
    }

    //Prevent exception in IE
    if (propValue && propValue.toLowerCase) {
      return propValue.toLowerCase();
    } else {
      return propValue;
    }
  };

  /**
   * Checks to see if target element (or parents) position is fixed or not
   *
   * @api private
   * @method _isFixed
   * @param {Object} element
   * @returns Boolean
   */
  function _isFixed (element) {
    var p = element.parentNode;

    if (p.nodeName === 'HTML') {
      return false;
    }

    if (_getPropValue(element, 'position') == 'fixed') {
      return true;
    }

    return _isFixed(p);
  };

  /**
   * Provides a cross-browser way to get the screen dimensions
   * via: http://stackoverflow.com/questions/5864467/internet-explorer-innerheight
   *
   * @api private
   * @method _getWinSize
   * @returns {Object} width and height attributes
   */
  function _getWinSize() {
    if (window.innerWidth != undefined) {
      return { width: window.innerWidth, height: window.innerHeight };
    } else {
      var D = document.documentElement;
      return { width: D.clientWidth, height: D.clientHeight };
    }
  }

  /**
   * Add overlay layer to the page
   * http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
   *
   * @api private
   * @method _elementInViewport
   * @param {Object} el
   */
  function _elementInViewport(el) {
    var rect = el.getBoundingClientRect();

    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      (rect.bottom+80) <= window.innerHeight && // add 80 to get the text right
      rect.right <= window.innerWidth
    );
  }

  /**
   * Add overlay layer to the page
   *
   * @api private
   * @method _addOverlayLayer
   * @param {Object} targetElm
   */
  function _addOverlayLayer(targetElm) {
    var overlayLayer = document.createElement('div'),
        styleText = '',
        self = this;

    //set css class name
    overlayLayer.className = 'introjs-overlay';

    //check if the target element is body, we should calculate the size of overlay layer in a better way
    if (targetElm.tagName.toLowerCase() === 'body') {
      styleText += 'top: 0;bottom: 0; left: 0;right: 0;position: fixed;';
      overlayLayer.setAttribute('style', styleText);
    } else {
      //set overlay layer position
      var elementPosition = _getOffset(targetElm);
      if (elementPosition) {
        styleText += 'width: ' + elementPosition.width + 'px; height:' + elementPosition.height + 'px; top:' + elementPosition.top + 'px;left: ' + elementPosition.left + 'px;';
        overlayLayer.setAttribute('style', styleText);
      }
    }

    targetElm.appendChild(overlayLayer);

    overlayLayer.onclick = function() {
      if (self._options.exitOnOverlayClick == true) {

        //check if any callback is defined
        if (self._introExitCallback != undefined) {
          self._introExitCallback.call(self);
        }
        _exitIntro.call(self, targetElm);
      }
    };

    setTimeout(function() {
      styleText += 'opacity: ' + self._options.overlayOpacity.toString() + ';';
      overlayLayer.setAttribute('style', styleText);
    }, 10);

    return true;
  };

  /**
   * Removes open hint (tooltip hint)
   *
   * @api private
   * @method _removeHintTooltip
   */
  function _removeHintTooltip() {
    var tooltip = this._targetElement.querySelector('.introjs-hintReference');


    if (tooltip) {
      var step = tooltip.getAttribute('data-step');
      tooltip.parentNode.removeChild(tooltip);
      return step;
    }
  };

  /**
   * Start parsing hint items
   *
   * @api private
   * @param {Object} targetElm
   * @method _startHint
   */
  function _populateHints(targetElm) {
    var self = this;
    this._introItems = []

    if (this._options.hints) {
      for (var i = 0, l = this._options.hints.length; i < l; i++) {
        var currentItem = _cloneObject(this._options.hints[i]);

        if (typeof(currentItem.element) === 'string') {
          //grab the element with given selector from the page
          currentItem.element = document.querySelector(currentItem.element);
        }

        currentItem.hintPosition = currentItem.hintPosition || 'top-middle';

        if (currentItem.element != null) {
          this._introItems.push(currentItem);
        }
      }
    } else {
      var hints = targetElm.querySelectorAll('*[data-hint]');

      if (hints.length < 1) {
        return false;
      }

      //first add intro items with data-step
      for (var i = 0, l = hints.length; i < l; i++) {
        var currentElement = hints[i];

        this._introItems.push({
          element: currentElement,
          hint: currentElement.getAttribute('data-hint'),
          hintPosition: currentElement.getAttribute('data-hintPosition') || this._options.hintPosition,
          tooltipClass: currentElement.getAttribute('data-tooltipClass'),
          position: currentElement.getAttribute('data-position') || this._options.tooltipPosition
        });
      }
    }

    _addHints.call(this);

    if (document.addEventListener) {
      document.addEventListener('click', _removeHintTooltip.bind(this), false);
      //for window resize
      window.addEventListener('resize', _reAlignHints.bind(this), true);
    } else if (document.attachEvent) { //IE
      //for window resize
      document.attachEvent('onclick', _removeHintTooltip.bind(this));
      document.attachEvent('onresize', _reAlignHints.bind(this));
    }
  };

  /**
   * Re-aligns all hint elements
   *
   * @api private
   * @method _reAlignHints
   */
  function _reAlignHints() {
    for (var i = 0, l = this._introItems.length; i < l; i++) {
      var item = this._introItems[i];

      if (typeof (item.targetElement) == 'undefined') continue;

      _alignHintPosition.call(this, item.hintPosition, item.element, item.targetElement)
    }
  }

  /**
   * Hide a hint
   *
   * @api private
   * @method _hideHint
   */
  function _hideHint(stepId) {
    _removeHintTooltip.call(this);
    var hint = this._targetElement.querySelector('.introjs-hint[data-step="' + stepId + '"]');

    if (hint) {
      hint.className += ' introjs-hidehint';
    }

    // call the callback function (if any)
    if (typeof (this._hintCloseCallback) !== 'undefined') {
      this._hintCloseCallback.call(this, stepId);
    }
  };

  /**
   * Add all available hints to the page
   *
   * @api private
   * @method _addHints
   */
  function _addHints() {
    var self = this;

    var oldHintsWrapper = document.querySelector('.introjs-hints');

    if (oldHintsWrapper != null) {
      hintsWrapper = oldHintsWrapper;
    } else {
      var hintsWrapper = document.createElement('div');
      hintsWrapper.className = 'introjs-hints';
    }

    for (var i = 0, l = this._introItems.length; i < l; i++) {
      var item = this._introItems[i];

      // avoid append a hint twice
      if (document.querySelector('.introjs-hint[data-step="' + i + '"]'))
        continue;

      var hint = document.createElement('a');
      _setAnchorAsButton(hint);

      (function (hint, item, i) {
        // when user clicks on the hint element
        hint.onclick = function(e) {
          var evt = e ? e : window.event;
          if (evt.stopPropagation)    evt.stopPropagation();
          if (evt.cancelBubble != null) evt.cancelBubble = true;

          _hintClick.call(self, hint, item, i);
        };
      }(hint, item, i));

      hint.className = 'introjs-hint';

      // hint's position should be fixed if the target element's position is fixed
      if (_isFixed(item.element)) {
        hint.className += ' introjs-fixedhint';
      }

      var hintDot = document.createElement('div');
      hintDot.className = 'introjs-hint-dot';
      var hintPulse = document.createElement('div');
      hintPulse.className = 'introjs-hint-pulse';

      hint.appendChild(hintDot);
      hint.appendChild(hintPulse);
      hint.setAttribute('data-step', i);

      // we swap the hint element with target element
      // because _setHelperLayerPosition uses `element` property
      item.targetElement = item.element;
      item.element = hint;

      // align the hint position
      _alignHintPosition.call(this, item.hintPosition, hint, item.targetElement);

      hintsWrapper.appendChild(hint);
    }

    // adding the hints wrapper
    document.body.appendChild(hintsWrapper);

    // call the callback function (if any)
    if (typeof (this._hintsAddedCallback) !== 'undefined') {
      this._hintsAddedCallback.call(this);
    }
  };

  /**
   * Aligns hint position
   *
   * @api private
   * @method _alignHintPosition
   * @param {String} position
   * @param {Object} hint
   * @param {Object} element
   */
  function _alignHintPosition(position, hint, element) {
    // get/calculate offset of target element
    var offset = _getOffset.call(this, element);

    // align the hint element
    switch (position) {
      default:
      case 'top-left':
        hint.style.left = offset.left + 'px';
        hint.style.top = offset.top + 'px';
        break;
      case 'top-right':
        hint.style.left = (offset.left + offset.width) + 'px';
        hint.style.top = offset.top + 'px';
        break;
      case 'bottom-left':
        hint.style.left = offset.left + 'px';
        hint.style.top = (offset.top + offset.height) + 'px';
        break;
      case 'bottom-right':
        hint.style.left = (offset.left + offset.width) + 'px';
        hint.style.top = (offset.top + offset.height) + 'px';
        break;
      case 'bottom-middle':
        hint.style.left = (offset.left + (offset.width / 2)) + 'px';
        hint.style.top = (offset.top + offset.height) + 'px';
        break;
      case 'top-middle':
        hint.style.left = (offset.left + (offset.width / 2)) + 'px';
        hint.style.top = offset.top + 'px';
        break;
    }
  };

  /**
   * Triggers when user clicks on the hint element
   *
   * @api private
   * @method _hintClick
   * @param {Object} hintElement
   * @param {Object} item
   * @param {Number} stepId
   */
  function _hintClick(hintElement, item, stepId) {
    // call the callback function (if any)
    if (typeof (this._hintClickCallback) !== 'undefined') {
      this._hintClickCallback.call(this, hintElement, item, stepId);
    }

    // remove all open tooltips
    var removedStep = _removeHintTooltip.call(this);

    // to toggle the tooltip
    if (parseInt(removedStep, 10) == stepId) {
      return;
    }

    var tooltipLayer = document.createElement('div');
    var tooltipTextLayer = document.createElement('div');
    var arrowLayer = document.createElement('div');
    var referenceLayer = document.createElement('div');

    tooltipLayer.className = 'introjs-tooltip';

    tooltipLayer.onclick = function (e) {
      //IE9 & Other Browsers
      if (e.stopPropagation) {
        e.stopPropagation();
      }
      //IE8 and Lower
      else {
        e.cancelBubble = true;
      }
    };

    tooltipTextLayer.className = 'introjs-tooltiptext';

    var tooltipWrapper = document.createElement('p');
    tooltipWrapper.innerHTML = item.hint;

    var closeButton = document.createElement('a');
    closeButton.className = 'introjs-button';
    closeButton.innerHTML = this._options.hintButtonLabel;
    closeButton.onclick = _hideHint.bind(this, stepId);

    tooltipTextLayer.appendChild(tooltipWrapper);
    tooltipTextLayer.appendChild(closeButton);

    arrowLayer.className = 'introjs-arrow';
    tooltipLayer.appendChild(arrowLayer);

    tooltipLayer.appendChild(tooltipTextLayer);

    // set current step for _placeTooltip function
    this._currentStep = hintElement.getAttribute('data-step');

    // align reference layer position
    referenceLayer.className = 'introjs-tooltipReferenceLayer introjs-hintReference';
    referenceLayer.setAttribute('data-step', hintElement.getAttribute('data-step'));
    _setHelperLayerPosition.call(this, referenceLayer);

    referenceLayer.appendChild(tooltipLayer);
    document.body.appendChild(referenceLayer);

    //set proper position
    _placeTooltip.call(this, hintElement, tooltipLayer, arrowLayer, null, true);
  };

  /**
   * Get an element position on the page
   * Thanks to `meouw`: http://stackoverflow.com/a/442474/375966
   *
   * @api private
   * @method _getOffset
   * @param {Object} element
   * @returns Element's position info
   */
  function _getOffset(element) {
    var elementPosition = {};

    //set width
    elementPosition.width = element.offsetWidth;

    //set height
    elementPosition.height = element.offsetHeight;

    //calculate element top and left
    var _x = 0;
    var _y = 0;
    while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) {
      _x += element.offsetLeft;
      _y += element.offsetTop;
      element = element.offsetParent;
    }
    //set top
    elementPosition.top = _y;
    //set left
    elementPosition.left = _x;

    return elementPosition;
  };

  /**
   * Gets the current progress percentage
   *
   * @api private
   * @method _getProgress
   * @returns current progress percentage
   */
  function _getProgress() {
    // Steps are 0 indexed
    var currentStep = parseInt((this._currentStep + 1), 10);
    return ((currentStep / this._introItems.length) * 100);
  };

  /**
   * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
   * via: http://stackoverflow.com/questions/171251/how-can-i-merge-properties-of-two-javascript-objects-dynamically
   *
   * @param obj1
   * @param obj2
   * @returns obj3 a new object based on obj1 and obj2
   */
  function _mergeOptions(obj1,obj2) {
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
  };

  var introJs = function (targetElm) {
    if (typeof (targetElm) === 'object') {
      //Ok, create a new instance
      return new IntroJs(targetElm);

    } else if (typeof (targetElm) === 'string') {
      //select the target element with query selector
      var targetElement = document.querySelector(targetElm);

      if (targetElement) {
        return new IntroJs(targetElement);
      } else {
        throw new Error('There is no element with given selector.');
      }
    } else {
      return new IntroJs(document.body);
    }
  };

  /**
   * Current IntroJs version
   *
   * @property version
   * @type String
   */
  introJs.version = VERSION;

  //Prototype
  introJs.fn = IntroJs.prototype = {
    clone: function () {
      return new IntroJs(this);
    },
    setOption: function(option, value) {
      this._options[option] = value;
      return this;
    },
    setOptions: function(options) {
      this._options = _mergeOptions(this._options, options);
      return this;
    },
    start: function () {
      _introForElement.call(this, this._targetElement);
      return this;
    },
    goToStep: function(step) {
      _goToStep.call(this, step);
      return this;
    },
    nextStep: function() {
      _nextStep.call(this);
      return this;
    },
    previousStep: function() {
      _previousStep.call(this);
      return this;
    },
    exit: function() {
      _exitIntro.call(this, this._targetElement);
      return this;
    },
    refresh: function() {
      // re-align intros
      _setHelperLayerPosition.call(this, document.querySelector('.introjs-helperLayer'));
      _setHelperLayerPosition.call(this, document.querySelector('.introjs-tooltipReferenceLayer'));

      //re-align hints
      _reAlignHints.call(this);
      return this;
    },
    onbeforechange: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._introBeforeChangeCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onbeforechange was not a function');
      }
      return this;
    },
    onchange: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._introChangeCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onchange was not a function.');
      }
      return this;
    },
    onafterchange: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._introAfterChangeCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onafterchange was not a function');
      }
      return this;
    },
    oncomplete: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._introCompleteCallback = providedCallback;
      } else {
        throw new Error('Provided callback for oncomplete was not a function.');
      }
      return this;
    },
    onhintsadded: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._hintsAddedCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onhintsadded was not a function.');
      }
      return this;
    },
    onhintclick: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._hintClickCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onhintclick was not a function.');
      }
      return this;
    },
    onhintclose: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._hintCloseCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onhintclose was not a function.');
      }
      return this;
    },
    onexit: function(providedCallback) {
      if (typeof (providedCallback) === 'function') {
        this._introExitCallback = providedCallback;
      } else {
        throw new Error('Provided callback for onexit was not a function.');
      }
      return this;
    },
    addHints: function() {
      _populateHints.call(this, this._targetElement);
      return this;
    },
    hideHint: function (stepId) {
      _hideHint.call(this, stepId);
      return this;
    }
  };

  exports.introJs = introJs;
  return introJs;
}));

},{}],188:[function(require,module,exports){
/*!
 * Copyright 2012, Chris Wanstrath
 * Released under the MIT License
 * https://github.com/defunkt/jquery-pjax
 */

(function($){

// When called on a container with a selector, fetches the href with
// ajax into the container or with the data-pjax attribute on the link
// itself.
//
// Tries to make sure the back button and ctrl+click work the way
// you'd expect.
//
// Exported as $.fn.pjax
//
// Accepts a jQuery ajax options object that may include these
// pjax specific options:
//
//
// container - Where to stick the response body. Usually a String selector.
//             $(container).html(xhr.responseBody)
//             (default: current jquery context)
//      push - Whether to pushState the URL. Defaults to true (of course).
//   replace - Want to use replaceState instead? That's cool.
//
// For convenience the second parameter can be either the container or
// the options object.
//
// Returns the jQuery object
function fnPjax(selector, container, options) {
  var context = this
  return this.on('click.pjax', selector, function(event) {
    var opts = $.extend({}, optionsFor(container, options))
    if (!opts.container)
      opts.container = $(this).attr('data-pjax') || context
    handleClick(event, opts)
  })
}

// Public: pjax on click handler
//
// Exported as $.pjax.click.
//
// event   - "click" jQuery.Event
// options - pjax options
//
// Examples
//
//   $(document).on('click', 'a', $.pjax.click)
//   // is the same as
//   $(document).pjax('a')
//
//  $(document).on('click', 'a', function(event) {
//    var container = $(this).closest('[data-pjax-container]')
//    $.pjax.click(event, container)
//  })
//
// Returns nothing.
function handleClick(event, container, options) {
  options = optionsFor(container, options)

  var link = event.currentTarget

  if (link.tagName.toUpperCase() !== 'A')
    throw "$.fn.pjax or $.pjax.click requires an anchor element"

  // Middle click, cmd click, and ctrl click should open
  // links in a new tab as normal.
  if ( event.which > 1 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey )
    return

  // Ignore cross origin links
  if ( location.protocol !== link.protocol || location.hostname !== link.hostname )
    return

  // Ignore case when a hash is being tacked on the current URL
  if ( link.href.indexOf('#') > -1 && stripHash(link) == stripHash(location) )
    return

  // Ignore event with default prevented
  if (event.isDefaultPrevented())
    return

  var defaults = {
    url: link.href,
    container: $(link).attr('data-pjax'),
    target: link
  }

  var opts = $.extend({}, defaults, options)
  var clickEvent = $.Event('pjax:click')
  $(link).trigger(clickEvent, [opts])

  if (!clickEvent.isDefaultPrevented()) {
    pjax(opts)
    event.preventDefault()
    $(link).trigger('pjax:clicked', [opts])
  }
}

// Public: pjax on form submit handler
//
// Exported as $.pjax.submit
//
// event   - "click" jQuery.Event
// options - pjax options
//
// Examples
//
//  $(document).on('submit', 'form', function(event) {
//    var container = $(this).closest('[data-pjax-container]')
//    $.pjax.submit(event, container)
//  })
//
// Returns nothing.
function handleSubmit(event, container, options) {
  options = optionsFor(container, options)

  var form = event.currentTarget

  if (form.tagName.toUpperCase() !== 'FORM')
    throw "$.pjax.submit requires a form element"

  var defaults = {
    type: form.method.toUpperCase(),
    url: form.action,
    container: $(form).attr('data-pjax'),
    target: form
  }

  if (defaults.type !== 'GET' && window.FormData !== undefined) {
    defaults.data = new FormData(form);
    defaults.processData = false;
    defaults.contentType = false;
  } else {
    // Can't handle file uploads, exit
    if ($(form).find(':file').length) {
      return;
    }

    // Fallback to manually serializing the fields
    defaults.data = $(form).serializeArray();
  }

  pjax($.extend({}, defaults, options))

  event.preventDefault()
}

// Loads a URL with ajax, puts the response body inside a container,
// then pushState()'s the loaded URL.
//
// Works just like $.ajax in that it accepts a jQuery ajax
// settings object (with keys like url, type, data, etc).
//
// Accepts these extra keys:
//
// container - Where to stick the response body.
//             $(container).html(xhr.responseBody)
//      push - Whether to pushState the URL. Defaults to true (of course).
//   replace - Want to use replaceState instead? That's cool.
//
// Use it just like $.ajax:
//
//   var xhr = $.pjax({ url: this.href, container: '#main' })
//   console.log( xhr.readyState )
//
// Returns whatever $.ajax returns.
function pjax(options) {
  options = $.extend(true, {}, $.ajaxSettings, pjax.defaults, options)

  if ($.isFunction(options.url)) {
    options.url = options.url()
  }

  var target = options.target

  var hash = parseURL(options.url).hash

  var context = options.context = findContainerFor(options.container)

  // We want the browser to maintain two separate internal caches: one
  // for pjax'd partial page loads and one for normal page loads.
  // Without adding this secret parameter, some browsers will often
  // confuse the two.
  if (!options.data) options.data = {}
  if ($.isArray(options.data)) {
    options.data.push({name: '_pjax', value: context.selector})
  } else {
    options.data._pjax = context.selector
  }

  function fire(type, args, props) {
    if (!props) props = {}
    props.relatedTarget = target
    var event = $.Event(type, props)
    context.trigger(event, args)
    return !event.isDefaultPrevented()
  }

  var timeoutTimer

  options.beforeSend = function(xhr, settings) {
    // No timeout for non-GET requests
    // Its not safe to request the resource again with a fallback method.
    if (settings.type !== 'GET') {
      settings.timeout = 0
    }

    xhr.setRequestHeader('X-PJAX', 'true')
    xhr.setRequestHeader('X-PJAX-Container', context.selector)

    if (!fire('pjax:beforeSend', [xhr, settings]))
      return false

    if (settings.timeout > 0) {
      timeoutTimer = setTimeout(function() {
        if (fire('pjax:timeout', [xhr, options]))
          xhr.abort('timeout')
      }, settings.timeout)

      // Clear timeout setting so jquerys internal timeout isn't invoked
      settings.timeout = 0
    }

    var url = parseURL(settings.url)
    if (hash) url.hash = hash
    options.requestUrl = stripInternalParams(url)
  }

  options.complete = function(xhr, textStatus) {
    if (timeoutTimer)
      clearTimeout(timeoutTimer)

    fire('pjax:complete', [xhr, textStatus, options])

    fire('pjax:end', [xhr, options])
  }

  options.error = function(xhr, textStatus, errorThrown) {
    var container = extractContainer("", xhr, options)

    var allowed = fire('pjax:error', [xhr, textStatus, errorThrown, options])
    if (options.type == 'GET' && textStatus !== 'abort' && allowed) {
      locationReplace(container.url)
    }
  }

  options.success = function(data, status, xhr) {
    var previousState = pjax.state;

    // If $.pjax.defaults.version is a function, invoke it first.
    // Otherwise it can be a static string.
    var currentVersion = (typeof $.pjax.defaults.version === 'function') ?
      $.pjax.defaults.version() :
      $.pjax.defaults.version

    var latestVersion = xhr.getResponseHeader('X-PJAX-Version')

    var container = extractContainer(data, xhr, options)

    var url = parseURL(container.url)
    if (hash) {
      url.hash = hash
      container.url = url.href
    }

    // If there is a layout version mismatch, hard load the new url
    if (currentVersion && latestVersion && currentVersion !== latestVersion) {
      locationReplace(container.url)
      return
    }

    // If the new response is missing a body, hard load the page
    if (!container.contents) {
      locationReplace(container.url)
      return
    }

    pjax.state = {
      id: options.id || uniqueId(),
      url: container.url,
      title: container.title,
      container: context.selector,
      fragment: options.fragment,
      timeout: options.timeout
    }

    if (options.push || options.replace) {
      window.history.replaceState(pjax.state, container.title, container.url)
    }

    // Clear out any focused controls before inserting new page contents.
    try {
      document.activeElement.blur()
    } catch (e) { }

    if (container.title) document.title = container.title

    fire('pjax:beforeReplace', [container.contents, options], {
      state: pjax.state,
      previousState: previousState
    })
    context.html(container.contents)

    // FF bug: Won't autofocus fields that are inserted via JS.
    // This behavior is incorrect. So if theres no current focus, autofocus
    // the last field.
    //
    // http://www.w3.org/html/wg/drafts/html/master/forms.html
    var autofocusEl = context.find('input[autofocus], textarea[autofocus]').last()[0]
    if (autofocusEl && document.activeElement !== autofocusEl) {
      autofocusEl.focus();
    }

    executeScriptTags(container.scripts)

    var scrollTo = options.scrollTo

    // Ensure browser scrolls to the element referenced by the URL anchor
    if (hash) {
      var name = decodeURIComponent(hash.slice(1))
      var target = document.getElementById(name) || document.getElementsByName(name)[0]
      if (target) scrollTo = $(target).offset().top
    }

    if (typeof scrollTo == 'number') $(window).scrollTop(scrollTo)

    fire('pjax:success', [data, status, xhr, options])
  }


  // Initialize pjax.state for the initial page load. Assume we're
  // using the container and options of the link we're loading for the
  // back button to the initial page. This ensures good back button
  // behavior.
  if (!pjax.state) {
    pjax.state = {
      id: uniqueId(),
      url: window.location.href,
      title: document.title,
      container: context.selector,
      fragment: options.fragment,
      timeout: options.timeout
    }
    window.history.replaceState(pjax.state, document.title)
  }

  // Cancel the current request if we're already pjaxing
  abortXHR(pjax.xhr)

  pjax.options = options
  var xhr = pjax.xhr = $.ajax(options)

  if (xhr.readyState > 0) {
    if (options.push && !options.replace) {
      // Cache current container element before replacing it
      cachePush(pjax.state.id, cloneContents(context))

      window.history.pushState(null, "", options.requestUrl)
    }

    fire('pjax:start', [xhr, options])
    fire('pjax:send', [xhr, options])
  }

  return pjax.xhr
}

// Public: Reload current page with pjax.
//
// Returns whatever $.pjax returns.
function pjaxReload(container, options) {
  var defaults = {
    url: window.location.href,
    push: false,
    replace: true,
    scrollTo: false
  }

  return pjax($.extend(defaults, optionsFor(container, options)))
}

// Internal: Hard replace current state with url.
//
// Work for around WebKit
//   https://bugs.webkit.org/show_bug.cgi?id=93506
//
// Returns nothing.
function locationReplace(url) {
  window.history.replaceState(null, "", pjax.state.url)
  window.location.replace(url)
}


var initialPop = true
var initialURL = window.location.href
var initialState = window.history.state

// Initialize $.pjax.state if possible
// Happens when reloading a page and coming forward from a different
// session history.
if (initialState && initialState.container) {
  pjax.state = initialState
}

// Non-webkit browsers don't fire an initial popstate event
if ('state' in window.history) {
  initialPop = false
}

// popstate handler takes care of the back and forward buttons
//
// You probably shouldn't use pjax on pages with other pushState
// stuff yet.
function onPjaxPopstate(event) {

  // Hitting back or forward should override any pending PJAX request.
  if (!initialPop) {
    abortXHR(pjax.xhr)
  }

  var previousState = pjax.state
  var state = event.state
  var direction

  if (state && state.container) {
    // When coming forward from a separate history session, will get an
    // initial pop with a state we are already at. Skip reloading the current
    // page.
    if (initialPop && initialURL == state.url) return

    if (previousState) {
      // If popping back to the same state, just skip.
      // Could be clicking back from hashchange rather than a pushState.
      if (previousState.id === state.id) return

      // Since state IDs always increase, we can deduce the navigation direction
      direction = previousState.id < state.id ? 'forward' : 'back'
    }

    var cache = cacheMapping[state.id] || []
    var container = $(cache[0] || state.container), contents = cache[1]

    if (container.length) {
      if (previousState) {
        // Cache current container before replacement and inform the
        // cache which direction the history shifted.
        cachePop(direction, previousState.id, cloneContents(container))
      }

      var popstateEvent = $.Event('pjax:popstate', {
        state: state,
        direction: direction
      })
      container.trigger(popstateEvent)

      var options = {
        id: state.id,
        url: state.url,
        container: container,
        push: false,
        fragment: state.fragment,
        timeout: state.timeout,
        scrollTo: false
      }

      if (contents) {
        container.trigger('pjax:start', [null, options])

        pjax.state = state
        if (state.title) document.title = state.title
        var beforeReplaceEvent = $.Event('pjax:beforeReplace', {
          state: state,
          previousState: previousState
        })
        container.trigger(beforeReplaceEvent, [contents, options])
        container.html(contents)

        container.trigger('pjax:end', [null, options])
      } else {
        pjax(options)
      }

      // Force reflow/relayout before the browser tries to restore the
      // scroll position.
      container[0].offsetHeight
    } else {
      locationReplace(location.href)
    }
  }
  initialPop = false
}

// Fallback version of main pjax function for browsers that don't
// support pushState.
//
// Returns nothing since it retriggers a hard form submission.
function fallbackPjax(options) {
  var url = $.isFunction(options.url) ? options.url() : options.url,
      method = options.type ? options.type.toUpperCase() : 'GET'

  var form = $('<form>', {
    method: method === 'GET' ? 'GET' : 'POST',
    action: url,
    style: 'display:none'
  })

  if (method !== 'GET' && method !== 'POST') {
    form.append($('<input>', {
      type: 'hidden',
      name: '_method',
      value: method.toLowerCase()
    }))
  }

  var data = options.data
  if (typeof data === 'string') {
    $.each(data.split('&'), function(index, value) {
      var pair = value.split('=')
      form.append($('<input>', {type: 'hidden', name: pair[0], value: pair[1]}))
    })
  } else if ($.isArray(data)) {
    $.each(data, function(index, value) {
      form.append($('<input>', {type: 'hidden', name: value.name, value: value.value}))
    })
  } else if (typeof data === 'object') {
    var key
    for (key in data)
      form.append($('<input>', {type: 'hidden', name: key, value: data[key]}))
  }

  $(document.body).append(form)
  form.submit()
}

// Internal: Abort an XmlHttpRequest if it hasn't been completed,
// also removing its event handlers.
function abortXHR(xhr) {
  if ( xhr && xhr.readyState < 4) {
    xhr.onreadystatechange = $.noop
    xhr.abort()
  }
}

// Internal: Generate unique id for state object.
//
// Use a timestamp instead of a counter since ids should still be
// unique across page loads.
//
// Returns Number.
function uniqueId() {
  return (new Date).getTime()
}

function cloneContents(container) {
  var cloned = container.clone()
  // Unmark script tags as already being eval'd so they can get executed again
  // when restored from cache. HAXX: Uses jQuery internal method.
  cloned.find('script').each(function(){
    if (!this.src) jQuery._data(this, 'globalEval', false)
  })
  return [container.selector, cloned.contents()]
}

// Internal: Strip internal query params from parsed URL.
//
// Returns sanitized url.href String.
function stripInternalParams(url) {
  url.search = url.search.replace(/([?&])(_pjax|_)=[^&]*/g, '')
  return url.href.replace(/\?($|#)/, '$1')
}

// Internal: Parse URL components and returns a Locationish object.
//
// url - String URL
//
// Returns HTMLAnchorElement that acts like Location.
function parseURL(url) {
  var a = document.createElement('a')
  a.href = url
  return a
}

// Internal: Return the `href` component of given URL object with the hash
// portion removed.
//
// location - Location or HTMLAnchorElement
//
// Returns String
function stripHash(location) {
  return location.href.replace(/#.*/, '')
}

// Internal: Build options Object for arguments.
//
// For convenience the first parameter can be either the container or
// the options object.
//
// Examples
//
//   optionsFor('#container')
//   // => {container: '#container'}
//
//   optionsFor('#container', {push: true})
//   // => {container: '#container', push: true}
//
//   optionsFor({container: '#container', push: true})
//   // => {container: '#container', push: true}
//
// Returns options Object.
function optionsFor(container, options) {
  // Both container and options
  if ( container && options )
    options.container = container

  // First argument is options Object
  else if ( $.isPlainObject(container) )
    options = container

  // Only container
  else
    options = {container: container}

  // Find and validate container
  if (options.container)
    options.container = findContainerFor(options.container)

  return options
}

// Internal: Find container element for a variety of inputs.
//
// Because we can't persist elements using the history API, we must be
// able to find a String selector that will consistently find the Element.
//
// container - A selector String, jQuery object, or DOM Element.
//
// Returns a jQuery object whose context is `document` and has a selector.
function findContainerFor(container) {
  container = $(container)

  if ( !container.length ) {
    throw "no pjax container for " + container.selector
  } else if ( container.selector !== '' && container.context === document ) {
    return container
  } else if ( container.attr('id') ) {
    return $('#' + container.attr('id'))
  } else {
    throw "cant get selector for pjax container!"
  }
}

// Internal: Filter and find all elements matching the selector.
//
// Where $.fn.find only matches descendants, findAll will test all the
// top level elements in the jQuery object as well.
//
// elems    - jQuery object of Elements
// selector - String selector to match
//
// Returns a jQuery object.
function findAll(elems, selector) {
  return elems.filter(selector).add(elems.find(selector));
}

function parseHTML(html) {
  return $.parseHTML(html, document, true)
}

// Internal: Extracts container and metadata from response.
//
// 1. Extracts X-PJAX-URL header if set
// 2. Extracts inline <title> tags
// 3. Builds response Element and extracts fragment if set
//
// data    - String response data
// xhr     - XHR response
// options - pjax options Object
//
// Returns an Object with url, title, and contents keys.
function extractContainer(data, xhr, options) {
  var obj = {}, fullDocument = /<html/i.test(data)

  // Prefer X-PJAX-URL header if it was set, otherwise fallback to
  // using the original requested url.
  var serverUrl = xhr.getResponseHeader('X-PJAX-URL')
  obj.url = serverUrl ? stripInternalParams(parseURL(serverUrl)) : options.requestUrl

  // Attempt to parse response html into elements
  if (fullDocument) {
    var $head = $(parseHTML(data.match(/<head[^>]*>([\s\S.]*)<\/head>/i)[0]))
    var $body = $(parseHTML(data.match(/<body[^>]*>([\s\S.]*)<\/body>/i)[0]))
  } else {
    var $head = $body = $(parseHTML(data))
  }

  // If response data is empty, return fast
  if ($body.length === 0)
    return obj

  // If there's a <title> tag in the header, use it as
  // the page's title.
  obj.title = findAll($head, 'title').last().text()

  if (options.fragment) {
    // If they specified a fragment, look for it in the response
    // and pull it out.
    if (options.fragment === 'body') {
      var $fragment = $body
    } else {
      var $fragment = findAll($body, options.fragment).first()
    }

    if ($fragment.length) {
      obj.contents = options.fragment === 'body' ? $fragment : $fragment.contents()

      // If there's no title, look for data-title and title attributes
      // on the fragment
      if (!obj.title)
        obj.title = $fragment.attr('title') || $fragment.data('title')
    }

  } else if (!fullDocument) {
    obj.contents = $body
  }

  // Clean up any <title> tags
  if (obj.contents) {
    // Remove any parent title elements
    obj.contents = obj.contents.not(function() { return $(this).is('title') })

    // Then scrub any titles from their descendants
    obj.contents.find('title').remove()

    // Gather all script[src] elements
    obj.scripts = findAll(obj.contents, 'script[src]').remove()
    obj.contents = obj.contents.not(obj.scripts)
  }

  // Trim any whitespace off the title
  if (obj.title) obj.title = $.trim(obj.title)

  return obj
}

// Load an execute scripts using standard script request.
//
// Avoids jQuery's traditional $.getScript which does a XHR request and
// globalEval.
//
// scripts - jQuery object of script Elements
//
// Returns nothing.
function executeScriptTags(scripts) {
  if (!scripts) return

  var existingScripts = $('script[src]')

  scripts.each(function() {
    var src = this.src
    var matchedScripts = existingScripts.filter(function() {
      return this.src === src
    })
    if (matchedScripts.length) return

    var script = document.createElement('script')
    var type = $(this).attr('type')
    if (type) script.type = type
    script.src = $(this).attr('src')
    document.head.appendChild(script)
  })
}

// Internal: History DOM caching class.
var cacheMapping      = {}
var cacheForwardStack = []
var cacheBackStack    = []

// Push previous state id and container contents into the history
// cache. Should be called in conjunction with `pushState` to save the
// previous container contents.
//
// id    - State ID Number
// value - DOM Element to cache
//
// Returns nothing.
function cachePush(id, value) {
  cacheMapping[id] = value
  cacheBackStack.push(id)

  // Remove all entries in forward history stack after pushing a new page.
  trimCacheStack(cacheForwardStack, 0)

  // Trim back history stack to max cache length.
  trimCacheStack(cacheBackStack, pjax.defaults.maxCacheLength)
}

// Shifts cache from directional history cache. Should be
// called on `popstate` with the previous state id and container
// contents.
//
// direction - "forward" or "back" String
// id        - State ID Number
// value     - DOM Element to cache
//
// Returns nothing.
function cachePop(direction, id, value) {
  var pushStack, popStack
  cacheMapping[id] = value

  if (direction === 'forward') {
    pushStack = cacheBackStack
    popStack  = cacheForwardStack
  } else {
    pushStack = cacheForwardStack
    popStack  = cacheBackStack
  }

  pushStack.push(id)
  if (id = popStack.pop())
    delete cacheMapping[id]

  // Trim whichever stack we just pushed to to max cache length.
  trimCacheStack(pushStack, pjax.defaults.maxCacheLength)
}

// Trim a cache stack (either cacheBackStack or cacheForwardStack) to be no
// longer than the specified length, deleting cached DOM elements as necessary.
//
// stack  - Array of state IDs
// length - Maximum length to trim to
//
// Returns nothing.
function trimCacheStack(stack, length) {
  while (stack.length > length)
    delete cacheMapping[stack.shift()]
}

// Public: Find version identifier for the initial page load.
//
// Returns String version or undefined.
function findVersion() {
  return $('meta').filter(function() {
    var name = $(this).attr('http-equiv')
    return name && name.toUpperCase() === 'X-PJAX-VERSION'
  }).attr('content')
}

// Install pjax functions on $.pjax to enable pushState behavior.
//
// Does nothing if already enabled.
//
// Examples
//
//     $.pjax.enable()
//
// Returns nothing.
function enable() {
  $.fn.pjax = fnPjax
  $.pjax = pjax
  $.pjax.enable = $.noop
  $.pjax.disable = disable
  $.pjax.click = handleClick
  $.pjax.submit = handleSubmit
  $.pjax.reload = pjaxReload
  $.pjax.defaults = {
    timeout: 650,
    push: true,
    replace: false,
    type: 'GET',
    dataType: 'html',
    scrollTo: 0,
    maxCacheLength: 20,
    version: findVersion
  }
  $(window).on('popstate.pjax', onPjaxPopstate)
}

// Disable pushState behavior.
//
// This is the case when a browser doesn't support pushState. It is
// sometimes useful to disable pushState for debugging on a modern
// browser.
//
// Examples
//
//     $.pjax.disable()
//
// Returns nothing.
function disable() {
  $.fn.pjax = function() { return this }
  $.pjax = fallbackPjax
  $.pjax.enable = enable
  $.pjax.disable = $.noop
  $.pjax.click = $.noop
  $.pjax.submit = $.noop
  $.pjax.reload = function() { window.location.reload() }

  $(window).off('popstate.pjax', onPjaxPopstate)
}


// Add the state property to jQuery's event object so we can use it in
// $(window).bind('popstate')
if ( $.inArray('state', $.event.props) < 0 )
  $.event.props.push('state')

// Is pjax supported by this browser?
$.support.pjax =
  window.history && window.history.pushState && window.history.replaceState &&
  // pushState isn't reliable on iOS until 5.
  !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]\D|WebApps\/.+CFNetwork)/)

$.support.pjax ? enable() : disable()

})(jQuery);

},{}],189:[function(require,module,exports){
/*!
 * The Final Countdown for jQuery v2.2.0 (http://hilios.github.io/jQuery.countdown/)
 * Copyright (c) 2016 Edson Hilios
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
(function(factory) {
    "use strict";
    if (typeof define === "function" && define.amd) {
        define([ "jquery" ], factory);
    } else {
        factory(jQuery);
    }
})(function($) {
    "use strict";
    var instances = [], matchers = [], defaultOptions = {
        precision: 100,
        elapse: false,
        defer: false
    };
    matchers.push(/^[0-9]*$/.source);
    matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
    matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/.source);
    matchers = new RegExp(matchers.join("|"));
    function parseDateString(dateString) {
        if (dateString instanceof Date) {
            return dateString;
        }
        if (String(dateString).match(matchers)) {
            if (String(dateString).match(/^[0-9]*$/)) {
                dateString = Number(dateString);
            }
            if (String(dateString).match(/\-/)) {
                dateString = String(dateString).replace(/\-/g, "/");
            }
            return new Date(dateString);
        } else {
            throw new Error("Couldn't cast `" + dateString + "` to a date object.");
        }
    }
    var DIRECTIVE_KEY_MAP = {
        Y: "years",
        m: "months",
        n: "daysToMonth",
        d: "daysToWeek",
        w: "weeks",
        W: "weeksToMonth",
        H: "hours",
        M: "minutes",
        S: "seconds",
        D: "totalDays",
        I: "totalHours",
        N: "totalMinutes",
        T: "totalSeconds"
    };
    function escapedRegExp(str) {
        var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
        return new RegExp(sanitize);
    }
    function strftime(offsetObject) {
        return function(format) {
            var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi);
            if (directives) {
                for (var i = 0, len = directives.length; i < len; ++i) {
                    var directive = directives[i].match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), regexp = escapedRegExp(directive[0]), modifier = directive[1] || "", plural = directive[3] || "", value = null;
                    directive = directive[2];
                    if (DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
                        value = DIRECTIVE_KEY_MAP[directive];
                        value = Number(offsetObject[value]);
                    }
                    if (value !== null) {
                        if (modifier === "!") {
                            value = pluralize(plural, value);
                        }
                        if (modifier === "") {
                            if (value < 10) {
                                value = "0" + value.toString();
                            }
                        }
                        format = format.replace(regexp, value.toString());
                    }
                }
            }
            format = format.replace(/%%/, "%");
            return format;
        };
    }
    function pluralize(format, count) {
        var plural = "s", singular = "";
        if (format) {
            format = format.replace(/(:|;|\s)/gi, "").split(/\,/);
            if (format.length === 1) {
                plural = format[0];
            } else {
                singular = format[0];
                plural = format[1];
            }
        }
        if (Math.abs(count) > 1) {
            return plural;
        } else {
            return singular;
        }
    }
    var Countdown = function(el, finalDate, options) {
        this.el = el;
        this.$el = $(el);
        this.interval = null;
        this.offset = {};
        this.options = $.extend({}, defaultOptions);
        this.instanceNumber = instances.length;
        instances.push(this);
        this.$el.data("countdown-instance", this.instanceNumber);
        if (options) {
            if (typeof options === "function") {
                this.$el.on("update.countdown", options);
                this.$el.on("stoped.countdown", options);
                this.$el.on("finish.countdown", options);
            } else {
                this.options = $.extend({}, defaultOptions, options);
            }
        }
        this.setFinalDate(finalDate);
        if (this.options.defer === false) {
            this.start();
        }
    };
    $.extend(Countdown.prototype, {
        start: function() {
            if (this.interval !== null) {
                clearInterval(this.interval);
            }
            var self = this;
            this.update();
            this.interval = setInterval(function() {
                self.update.call(self);
            }, this.options.precision);
        },
        stop: function() {
            clearInterval(this.interval);
            this.interval = null;
            this.dispatchEvent("stoped");
        },
        toggle: function() {
            if (this.interval) {
                this.stop();
            } else {
                this.start();
            }
        },
        pause: function() {
            this.stop();
        },
        resume: function() {
            this.start();
        },
        remove: function() {
            this.stop.call(this);
            instances[this.instanceNumber] = null;
            delete this.$el.data().countdownInstance;
        },
        setFinalDate: function(value) {
            this.finalDate = parseDateString(value);
        },
        update: function() {
            if (this.$el.closest("html").length === 0) {
                this.remove();
                return;
            }
            var hasEventsAttached = $._data(this.el, "events") !== undefined, now = new Date(), newTotalSecsLeft;
            newTotalSecsLeft = this.finalDate.getTime() - now.getTime();
            newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1e3);
            newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : Math.abs(newTotalSecsLeft);
            if (this.totalSecsLeft === newTotalSecsLeft || !hasEventsAttached) {
                return;
            } else {
                this.totalSecsLeft = newTotalSecsLeft;
            }
            this.elapsed = now >= this.finalDate;
            this.offset = {
                seconds: this.totalSecsLeft % 60,
                minutes: Math.floor(this.totalSecsLeft / 60) % 60,
                hours: Math.floor(this.totalSecsLeft / 60 / 60) % 24,
                days: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
                daysToWeek: Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
                daysToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368),
                weeks: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
                weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4,
                months: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368),
                years: Math.abs(this.finalDate.getFullYear() - now.getFullYear()),
                totalDays: Math.floor(this.totalSecsLeft / 60 / 60 / 24),
                totalHours: Math.floor(this.totalSecsLeft / 60 / 60),
                totalMinutes: Math.floor(this.totalSecsLeft / 60),
                totalSeconds: this.totalSecsLeft
            };
            if (!this.options.elapse && this.totalSecsLeft === 0) {
                this.stop();
                this.dispatchEvent("finish");
            } else {
                this.dispatchEvent("update");
            }
        },
        dispatchEvent: function(eventName) {
            var event = $.Event(eventName + ".countdown");
            event.finalDate = this.finalDate;
            event.elapsed = this.elapsed;
            event.offset = $.extend({}, this.offset);
            event.strftime = strftime(this.offset);
            this.$el.trigger(event);
        }
    });
    $.fn.countdown = function() {
        var argumentsArray = Array.prototype.slice.call(arguments, 0);
        return this.each(function() {
            var instanceNumber = $(this).data("countdown-instance");
            if (instanceNumber !== undefined) {
                var instance = instances[instanceNumber], method = argumentsArray[0];
                if (Countdown.prototype.hasOwnProperty(method)) {
                    instance[method].apply(instance, argumentsArray.slice(1));
                } else if (String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
                    instance.setFinalDate.call(instance, method);
                    instance.start();
                } else {
                    $.error("Method %s does not exist on jQuery.countdown".replace(/\%s/gi, method));
                }
            } else {
                new Countdown(this, argumentsArray[0], argumentsArray[1]);
            }
        });
    };
});


},{}],190:[function(require,module,exports){
/*
===============================================================================
    Author:     Eric M. Barnard - @ericmbarnard                                
    License:    MIT (http://opensource.org/licenses/mit-license.php)           
                                                                               
    Description: Validation Library for KnockoutJS                             
===============================================================================
*/

(function (factory) {
    // Module systems magic dance.

    if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        // CommonJS or Node: hard-coded dependency on "knockout"
        factory(require("knockout"), exports);
    } else if (typeof define === "function" && define["amd"]) {
        // AMD anonymous module with hard-coded dependency on "knockout"
        define(["knockout", "exports"], factory);
    } else {
        // <script> tag: use the global `ko` object, attaching a `mapping` property
        factory(ko, ko.validation = {});
    }
}(function ( ko, exports ) {

    if (typeof (ko) === undefined) { throw 'Knockout is required, please ensure it is loaded before loading this validation plug-in'; }

    if (typeof define === "function" && define["amd"]) {
        exports = ko.validation = {};
    }

    var defaults = {
        registerExtenders: true,
        messagesOnModified: true,
        errorsAsTitleOnModified: false, // shows the error when hovering the input field (decorateElement must be true)
        messageTemplate: null,
        insertMessages: true,           // automatically inserts validation messages as <span></span>
        parseInputAttributes: false,    // parses the HTML5 validation attribute from a form element and adds that to the object
        writeInputAttributes: false,    // adds HTML5 input validation attributes to form elements that ko observable's are bound to
        decorateElement: false,         // false to keep backward compatibility
        errorClass: null,               // single class for error message and element
        errorElementClass: 'validationElement',  // class to decorate error element
        errorMessageClass: 'validationMessage',  // class to decorate error message
        grouping: {
            deep: false,        //by default grouping is shallow
            observable: true    //and using observables
        }
    };

    // make a copy  so we can use 'reset' later
    var configuration = ko.utils.extend({}, defaults);

    var html5Attributes = ['required', 'pattern', 'min', 'max', 'step'];

    var async = function (expr) {
        if (window.setImmediate) { window.setImmediate(expr); }
        else { window.setTimeout(expr, 0); }
    };

    //#region Utilities

    var utils = (function () {
        var seedId = new Date().getTime();

        var domData = {}; //hash of data objects that we reference from dom elements
        var domDataKey = '__ko_validation__';

        return {
            isArray: function (o) {
                return o.isArray || Object.prototype.toString.call(o) === '[object Array]';
            },
            isObject: function (o) {
                return o !== null && typeof o === 'object';
            },
            values: function (o) {
                var r = [];
                for (var i in o) {
                    if (o.hasOwnProperty(i)) {
                        r.push(o[i]);
                    }
                }
                return r;
            },
            getValue: function (o) {
                return (typeof o === 'function' ? o() : o);
            },
            hasAttribute: function (node, attr) {
                return node.getAttribute(attr) !== null;
            },
            isValidatable: function (o) {
                return o && o.rules && o.isValid && o.isModified;
            },
            insertAfter: function (node, newNode) {
                node.parentNode.insertBefore(newNode, node.nextSibling);
            },
            newId: function () {
                return seedId += 1;
            },
            getConfigOptions: function (element) {
                var options = utils.contextFor(element);

                return options || configuration;
            },
            setDomData: function (node, data) {
                var key = node[domDataKey];

                if (!key) {
                    node[domDataKey] = key = utils.newId();
                }

                domData[key] = data;
            },
            getDomData: function (node) {
                var key = node[domDataKey];

                if (!key) {
                    return undefined;
                }

                return domData[key];
            },
            contextFor: function (node) {
                switch (node.nodeType) {
                    case 1:
                    case 8:
                        var context = utils.getDomData(node);
                        if (context) return context;
                        if (node.parentNode) return utils.contextFor(node.parentNode);
                        break;
                }
                return undefined;
            },
            isEmptyVal: function (val) {
                if (val === undefined) {
                    return true;
                }
                if (val === null) {
                    return true;
                }
                if (val === "") {
                    return true;
                }
            }
        };
    } ());

    //#endregion

    //#region Public API
    var validation = (function () {

        var isInitialized = 0;

        return {
            utils: utils,

            //Call this on startup
            //any config can be overridden with the passed in options
            init: function (options, force) {
                //done run this multiple times if we don't really want to
                if (isInitialized > 0 && !force) {
                    return;
                }

                //becuase we will be accessing options properties it has to be an object at least
                options = options || {};
                //if specific error classes are not provided then apply generic errorClass
                //it has to be done on option so that options.errorClass can override default
                //errorElementClass and errorMessage class but not those provided in options
                options.errorElementClass = options.errorElementClass || options.errorClass || configuration.errorElementClass;
                options.errorMessageClass = options.errorMessageClass || options.errorClass || configuration.errorMessageClass;

                ko.utils.extend(configuration, options);

                if (configuration.registerExtenders) {
                    exports.registerExtenders();
                }

                isInitialized = 1;
            },
            // backwards compatability
            configure: function (options) { exports.init(options); },

            // resets the config back to its original state
            reset: function () { configuration = $.extend(configuration, defaults); },

            // recursivly walks a viewModel and creates an object that
            // provides validation information for the entire viewModel
            // obj -> the viewModel to walk
            // options -> {
            //      deep: false, // if true, will walk past the first level of viewModel properties
            //      observable: false // if true, returns a computed observable indicating if the viewModel is valid
            // }
            group: function group(obj, options) { // array of observables or viewModel
                var options = ko.utils.extend(configuration.grouping, options),
                validatables = ko.observableArray([]),
                result = null,

                //anonymous, immediate function to traverse objects hierarchically
                //if !options.deep then it will stop on top level
                traverse = function traverse(obj, level) {
                    var objValues = [],
                        val = ko.utils.unwrapObservable(obj);

                    //default level value depends on deep option.
                    level = (level !== undefined ? level : options.deep ? 1 : -1);

                    // if object is observable then add it to the list
                    if (ko.isObservable(obj)) {

                        //make sure it is validatable object
                        if (!obj.isValid) obj.extend({ validatable: true });
                        validatables.push(obj);
                    }

                    //get list of values either from array or object but ignore non-objects
                    if (val) {
                        if (utils.isArray(val)) {
                            objValues = val;
                        } else if (utils.isObject(val)) {
                            objValues = utils.values(val);
                        }
                    }

                    //process recurisvely if it is deep grouping
                    if (level !== 0) {
                        ko.utils.arrayForEach(objValues, function (observable) {

                            //but not falsy things and not HTML Elements
                            if (observable && !observable.nodeType) traverse(observable, level + 1);
                        });
                    }
                };

                //if using observables then traverse structure once and add observables
                if (options.observable) {

                    traverse(obj);

                    result = ko.computed(function () {
                        var errors = [];
                        ko.utils.arrayForEach(validatables(), function (observable) {
                            if (!observable.isValid()) {
                                errors.push(observable.error);
                            }
                        });
                        return errors;
                    });

                } else { //if not using observables then every call to error() should traverse the structure
                    result = function () {
                        var errors = [];
                        validatables([]); //clear validatables
                        traverse(obj); // and traverse tree again
                        ko.utils.arrayForEach(validatables(), function (observable) {
                            if (!observable.isValid()) {
                                errors.push(observable.error);
                            }
                        });
                        return errors;
                    };


                }

                result.showAllMessages = function (show) { // thanks @heliosPortal
                    if (show == undefined) //default to true
                        show = true;

                    // ensure we have latest changes
                    result();

                    ko.utils.arrayForEach(validatables(), function (observable) {
                        observable.isModified(show);
                    });
                };

                obj.errors = result;
                obj.isValid = function () {
                    return obj.errors().length === 0;
                };
                obj.isAnyMessageShown = function() {
                    var invalidAndModifiedPresent = false;
                    
                    // ensure we have latest changes
                    result();
                    
                    ko.utils.arrayForEach(validatables(), function (observable) {
                        if (!observable.isValid() && observable.isModified()) {
                            invalidAndModifiedPresent = true;
                        }
                    });
                    return invalidAndModifiedPresent;
                };

                return result;
            },

            formatMessage: function (message, params) {
                if (typeof (message) === 'function')
                    return message(params);
                return message.replace(/\{0\}/gi, params);
            },

            // addRule:
            // This takes in a ko.observable and a Rule Context - which is just a rule name and params to supply to the validator
            // ie: ko.validation.addRule(myObservable, {
            //          rule: 'required',
            //          params: true
            //      });
            //
            addRule: function (observable, rule) {
                observable.extend({ validatable: true });

                //push a Rule Context to the observables local array of Rule Contexts
                observable.rules.push(rule);
                return observable;
            },

            // addAnonymousRule:
            // Anonymous Rules essentially have all the properties of a Rule, but are only specific for a certain property
            // and developers typically are wanting to add them on the fly or not register a rule with the 'ko.validation.rules' object
            //
            // Example:
            // var test = ko.observable('something').extend{(
            //      validation: {
            //          validator: function(val, someOtherVal){
            //              return true;
            //          },
            //          message: "Something must be really wrong!',
            //          params: true
            //      }
            //  )};
            addAnonymousRule: function (observable, ruleObj) {
                var ruleName = utils.newId();

                if ( ruleObj['message'] === undefined ) {
                    ruleObj['message'] = 'Error';
                }

                //Create an anonymous rule to reference
                exports.rules[ruleName] = ruleObj;

                //add the anonymous rule to the observable
                exports.addRule(observable, {
                    rule: ruleName,
                    params: ruleObj.params
                });
            },

            addExtender: function (ruleName) {
                ko.extenders[ruleName] = function (observable, params) {
                    //params can come in a few flavors
                    // 1. Just the params to be passed to the validator
                    // 2. An object containing the Message to be used and the Params to pass to the validator
                    // 3. A condition when the validation rule to be applied
                    //
                    // Example:
                    // var test = ko.observable(3).extend({
                    //      max: {
                    //          message: 'This special field has a Max of {0}',
                    //          params: 2,
                    //          onlyIf: function() {
                    //                      return specialField.IsVisible();
                    //                  }
                    //      }
                    //  )};
                    //
                    if (params.message || params.onlyIf) { //if it has a message or condition object, then its an object literal to use
                        return exports.addRule(observable, {
                            rule: ruleName,
                            message: params.message,
                            params: utils.isEmptyVal(params.params) ? true : params.params,
                            condition: params.onlyIf
                        });
                    } else {
                        return exports.addRule(observable, {
                            rule: ruleName,
                            params: params
                        });
                    }
                };
            },

            // loops through all ko.validation.rules and adds them as extenders to
            // ko.extenders
            registerExtenders: function () { // root extenders optional, use 'validation' extender if would cause conflicts
                if (configuration.registerExtenders) {
                    for (var ruleName in exports.rules) {
                        if (exports.rules.hasOwnProperty(ruleName)) {
                            if (!ko.extenders[ruleName]) {
                                exports.addExtender(ruleName);
                            }
                        }
                    }
                }
            },

            //creates a span next to the @element with the specified error class
            insertValidationMessage: function (element) {
                var span = document.createElement('SPAN');
                span.className = utils.getConfigOptions(element).errorMessageClass;
                utils.insertAfter(element, span);
                return span;
            },

            // if html-5 validation attributes have been specified, this parses
            // the attributes on @element
            parseInputValidationAttributes: function (element, valueAccessor) {
                ko.utils.arrayForEach(html5Attributes, function (attr) {
                    if (utils.hasAttribute(element, attr)) {
                        exports.addRule(valueAccessor(), {
                            rule: attr,
                            params: element.getAttribute(attr) || true
                        });
                    }
                });
            },

            // writes html5 validation attributes on the element passed in
            writeInputValidationAttributes: function (element, valueAccessor) {
                var observable = valueAccessor();

                if (!observable || !observable.rules) {
                    return;
                }

                var contexts = observable.rules(); // observable array

                // loop through the attributes and add the information needed
                ko.utils.arrayForEach(html5Attributes, function (attr) {
                    var params;
                    var ctx = ko.utils.arrayFirst(contexts, function (ctx) {
                        return ctx.rule.toLowerCase() === attr.toLowerCase();
                    });

                    if (!ctx)
                        return;

                    params = ctx.params;

                    // we have to do some special things for the pattern validation
                    if (ctx.rule == "pattern") {
                        if (ctx.params instanceof RegExp) {
                            params = ctx.params.source; // we need the pure string representation of the RegExpr without the //gi stuff
                        }
                    }

                    // we have a rule matching a validation attribute at this point
                    // so lets add it to the element along with the params
                    element.setAttribute(attr, params);
                });

                contexts = null;
            }
        };
    } ());
    //#endregion

    //#region Core Validation Rules

    //Validation Rules:
    // You can view and override messages or rules via:
    // ko.validation.rules[ruleName]
    //
    // To implement a custom Rule, simply use this template:
    // ko.validation.rules['<custom rule name>'] = {
    //      validator: function (val, param) {
    //          <custom logic>
    //          return <true or false>;
    //      },
    //      message: '<custom validation message>' //optionally you can also use a '{0}' to denote a placeholder that will be replaced with your 'param'
    // };
    //
    // Example:
    // ko.validation.rules['mustEqual'] = {
    //      validator: function( val, mustEqualVal ){
    //          return val === mustEqualVal;
    //      },
    //      message: 'This field must equal {0}'
    // };
    //
    validation.rules = {};
    validation.rules['required'] = {
        validator: function (val, required) {
            var stringTrimRegEx = /^\s+|\s+$/g,
                testVal;

            if (val === undefined || val === null) {
                return !required;
            }

            testVal = val;
            if (typeof (val) == "string") {
                testVal = val.replace(stringTrimRegEx, '');
            }

            if (!required) // if they passed: { required: false }, then don't require this
                return true;

            return ((testVal + '').length > 0);
        },
        message: 'This field is required.'
    };

    validation.rules['min'] = {
        validator: function (val, min) {
            return utils.isEmptyVal(val) || val >= min;
        },
        message: 'Please enter a value greater than or equal to {0}.'
    };

    validation.rules['max'] = {
        validator: function (val, max) {
            return utils.isEmptyVal(val) || val <= max;
        },
        message: 'Please enter a value less than or equal to {0}.'
    };

    validation.rules['minLength'] = {
        validator: function (val, minLength) {
            return utils.isEmptyVal(val) || val.length >= minLength;
        },
        message: 'Please enter at least {0} characters.'
    };

    validation.rules['maxLength'] = {
        validator: function (val, maxLength) {
            return utils.isEmptyVal(val) || val.length <= maxLength;
        },
        message: 'Please enter no more than {0} characters.'
    };

    validation.rules['pattern'] = {
        validator: function (val, regex) {
            return utils.isEmptyVal(val) || val.match(regex) != null;
        },
        message: 'Please check this value.'
    };

    validation.rules['step'] = {
        validator: function (val, step) {

            // in order to handle steps of .1 & .01 etc.. Modulus won't work
            // if the value is a decimal, so we have to correct for that
            return utils.isEmptyVal(val) || (val * 100) % (step * 100) === 0;
        },
        message: 'The value must increment by {0}'
    };

    validation.rules['email'] = {
        validator: function (val, validate) {
            if (!validate) return true;

            //I think an empty email address is also a valid entry
            //if one want's to enforce entry it should be done with 'required: true'
            return utils.isEmptyVal(val) || (
                // jquery validate regex - thanks Scott Gonzalez
                validate && /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(val)
            );
        },
        message: 'Please enter a proper email address'
    };

    validation.rules['date'] = {
        validator: function (value, validate) {
            if (!validate) return true;
            return utils.isEmptyVal(value) || (validate && !/Invalid|NaN/.test(new Date(value)));
        },
        message: 'Please enter a proper date'
    };

    validation.rules['dateISO'] = {
        validator: function (value, validate) {
            if (!validate) return true;
            return utils.isEmptyVal(value) || (validate && /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value));
        },
        message: 'Please enter a proper date'
    };

    validation.rules['number'] = {
        validator: function (value, validate) {
            if (!validate) return true;
            return utils.isEmptyVal(value) || (validate && /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value));
        },
        message: 'Please enter a number'
    };

    validation.rules['digit'] = {
        validator: function (value, validate) {
            if (!validate) return true;
            return utils.isEmptyVal(value) || (validate && /^\d+$/.test(value));
        },
        message: 'Please enter a digit'
    };

    validation.rules['phoneUS'] = {
        validator: function (phoneNumber, validate) {
            if (!validate) return true;
            if (typeof (phoneNumber) !== 'string') { return false; }
            if (utils.isEmptyVal(phoneNumber)) { return true; } // makes it optional, use 'required' rule if it should be required
            phoneNumber = phoneNumber.replace(/\s+/g, "");
            return validate && phoneNumber.length > 9 && phoneNumber.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
        },
        message: 'Please specify a valid phone number'
    };

    validation.rules['equal'] = {
        validator: function (val, params) {
            var otherValue = params;
            return val === utils.getValue(otherValue);
        },
        message: 'Values must equal'
    };

    validation.rules['notEqual'] = {
        validator: function (val, params) {
            var otherValue = params;
            return val !== utils.getValue(otherValue);
        },
        message: 'Please choose another value.'
    };

    //unique in collection
    // options are:
    //    collection: array or function returning (observable) array
    //              in which the value has to be unique
    //    valueAccessor: function that returns value from an object stored in collection
    //              if it is null the value is compared directly
    //    external: set to true when object you are validating is automatically updating collection
    validation.rules['unique'] = {
        validator: function (val, options) {
            var c = utils.getValue(options.collection),
                external = utils.getValue(options.externalValue),
                counter = 0;

            if (!val || !c) return true;

            ko.utils.arrayFilter(ko.utils.unwrapObservable(c), function (item) {
                if (val === (options.valueAccessor ? options.valueAccessor(item) : item)) counter++;
            });
            // if value is external even 1 same value in collection means the value is not unique
            return counter < (external !== undefined && val !== external ? 1 : 2);
        },
        message: 'Please make sure the value is unique.'
    };


    //now register all of these!
    (function () {
        validation.registerExtenders();
    } ());

    //#endregion

    //#region Knockout Binding Handlers

    // The core binding handler
    // this allows us to setup any value binding that internally always
    // performs the same functionality
    ko.bindingHandlers['validationCore'] = (function () {

        return {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var config = utils.getConfigOptions(element);

                // parse html5 input validation attributes, optional feature
                if (config.parseInputAttributes) {
                    async(function () { exports.parseInputValidationAttributes(element, valueAccessor) });
                }

                // if requested insert message element and apply bindings
                if (config.insertMessages && utils.isValidatable(valueAccessor())) {

                    // insert the <span></span>
                    var validationMessageElement = exports.insertValidationMessage(element);

                    // if we're told to use a template, make sure that gets rendered
                    if (config.messageTemplate) {
                        ko.renderTemplate(config.messageTemplate, { field: valueAccessor() }, null, validationMessageElement, 'replaceNode');
                    } else {
                        ko.applyBindingsToNode(validationMessageElement, { validationMessage: valueAccessor() });
                    }
                }

                // write the html5 attributes if indicated by the config
                if (config.writeInputAttributes && utils.isValidatable(valueAccessor())) {

                    exports.writeInputValidationAttributes(element, valueAccessor);
                }

                // if requested, add binding to decorate element
                if (config.decorateElement && utils.isValidatable(valueAccessor())) {
                    ko.applyBindingsToNode(element, { validationElement: valueAccessor() });
                }
            },

            update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                // hook for future extensibility
            }
        };

    }());

    // override for KO's default 'value' binding
    (function () {
        var init = ko.bindingHandlers['value'].init;

        ko.bindingHandlers['value'].init = function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

            init(element, valueAccessor, allBindingsAccessor);

            return ko.bindingHandlers['validationCore'].init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
        };
    } ());


    ko.bindingHandlers['validationMessage'] = { // individual error message, if modified or post binding
        update: function (element, valueAccessor) {
            var obsv = valueAccessor(),
                config = utils.getConfigOptions(element),
                val = ko.utils.unwrapObservable(obsv),
                msg = null,
                isModified = false,
                isValid = false;
                
            obsv.extend({ validatable: true });

            isModified = obsv.isModified();
            isValid = obsv.isValid();
            
            // create a handler to correctly return an error message
            var errorMsgAccessor = function () {
                if (!config.messagesOnModified || isModified) {
                    return isValid ? null : obsv.error;
                } else {
                    return null;
                }
            };

            //toggle visibility on validation messages when validation hasn't been evaluated, or when the object isValid
            var visiblityAccessor = function () {
                return isModified ? !isValid : false;
            };

            ko.bindingHandlers.text.update(element, errorMsgAccessor);
            ko.bindingHandlers.visible.update(element, visiblityAccessor);
        }
    };

    ko.bindingHandlers['validationElement'] = {
        update: function (element, valueAccessor) {
            var obsv = valueAccessor(),
                config = utils.getConfigOptions(element),
                val = ko.utils.unwrapObservable(obsv),
                msg = null,
                isModified = false,
                isValid = false;

            obsv.extend({ validatable: true });

            isModified = obsv.isModified();
            isValid = obsv.isValid();

            // create an evaluator function that will return something like:
            // css: { validationElement: true }
            var cssSettingsAccessor = function () {
                var css = {};

                var shouldShow = (isModified ? !isValid : false);

                if (!config.decorateElement) { shouldShow = false; }

                // css: { validationElement: false }
                css[config.errorElementClass] = shouldShow;

                return css;
            };

            //add or remove class on the element;
            ko.bindingHandlers.css.update(element, cssSettingsAccessor);

            var origTitle = element.getAttribute('data-orig-title');
            var elementTitle = element.title;
            var titleIsErrorMsg = element.getAttribute('data-orig-title') == "true"

            var errorMsgTitleAccessor = function () {
                if (!config.errorsAsTitleOnModified || isModified) {
                    if (!isValid) {
                        return { title: obsv.error, 'data-orig-title': origTitle || elementTitle };
                    } else {
                        return { title: origTitle || elementTitle, 'data-orig-title': null };
                    }
                }
            };
            ko.bindingHandlers.attr.update(element, errorMsgTitleAccessor);
        }
    };

    // ValidationOptions:
    // This binding handler allows you to override the initial config by setting any of the options for a specific element or context of elements
    //
    // Example:
    // <div data-bind="validationOptions: { insertMessages: true, messageTemplate: 'customTemplate', errorMessageClass: 'mySpecialClass'}">
    //      <input type="text" data-bind="value: someValue"/>
    //      <input type="text" data-bind="value: someValue2"/>
    // </div>
    ko.bindingHandlers['validationOptions'] = (function () {
        return {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var options = ko.utils.unwrapObservable(valueAccessor());
                if (options) {
                    var newConfig = ko.utils.extend({}, configuration);
                    ko.utils.extend(newConfig, options);

                    //store the validation options on the node so we can retrieve it later
                    utils.setDomData(element, newConfig);
                }
            }
        };
    } ());
    //#endregion

    //#region Knockout Extenders

    // Validation Extender:
    // This is for creating custom validation logic on the fly
    // Example:
    // var test = ko.observable('something').extend{(
    //      validation: {
    //          validator: function(val, someOtherVal){
    //              return true;
    //          },
    //          message: "Something must be really wrong!',
    //          params: true
    //      }
    //  )};
    ko.extenders['validation'] = function (observable, rules) { // allow single rule or array
        ko.utils.arrayForEach(utils.isArray(rules) ? rules : [rules], function (rule) {
            // the 'rule' being passed in here has no name to identify a core Rule,
            // so we add it as an anonymous rule
            // If the developer is wanting to use a core Rule, but use a different message see the 'addExtender' logic for examples
            exports.addAnonymousRule(observable, rule);
        });
        return observable;
    };

    //This is the extender that makes a Knockout Observable also 'Validatable'
    //examples include:
    // 1. var test = ko.observable('something').extend({validatable: true});
    // this will ensure that the Observable object is setup properly to respond to rules
    //
    // 2. test.extend({validatable: false});
    // this will remove the validation properties from the Observable object should you need to do that.
    ko.extenders['validatable'] = function (observable, enable) {
        if (enable && !utils.isValidatable(observable)) {

            observable.error = null; // holds the error message, we only need one since we stop processing validators when one is invalid

            // observable.rules:
            // ObservableArray of Rule Contexts, where a Rule Context is simply the name of a rule and the params to supply to it
            //
            // Rule Context = { rule: '<rule name>', params: '<passed in params>', message: '<Override of default Message>' }
            observable.rules = ko.observableArray(); //holds the rule Contexts to use as part of validation

            //in case async validation is occuring
            observable.isValidating = ko.observable(false);

            //the true holder of whether the observable is valid or not
            observable.__valid__ = ko.observable(true);

            observable.isModified = ko.observable(false);

            // we use a computed here to ensure that anytime a dependency changes, the
            // validation logic evaluates
            var h_obsValidationTrigger = ko.computed(function () {
                var obs = observable(),
                    ruleContexts = observable.rules();

                exports.validateObservable(observable);

                return true;
            });

            // a semi-protected observable
            observable.isValid = ko.computed(function () {
                return observable.__valid__();
            });

            //subscribe to changes in the observable
            var h_change = observable.subscribe(function () {
                observable.isModified(true);
            });

            observable._disposeValidation = function () {
                //first dispose of the subscriptions
                observable.isValid.dispose();
                observable.rules.removeAll();
                observable.isModified._subscriptions['change'] = [];
                observable.isValidating._subscriptions['change'] = [];
                observable.__valid__._subscriptions['change'] = [];
                h_change.dispose();
                h_obsValidationTrigger.dispose();

                delete observable['rules'];
                delete observable['error'];
                delete observable['isValid'];
                delete observable['isValidating'];
                delete observable['__valid__'];
                delete observable['isModified'];
            };
        } else if (enable === false && utils.isValidatable(observable)) {

            if (observable._disposeValidation) {
                observable._disposeValidation();
            }
        }
        return observable;
    };

    function validateSync(observable, rule, ctx) {
        //Execute the validator and see if its valid
        if (!rule.validator(observable(), ctx.params === undefined ? true : ctx.params)) { // default param is true, eg. required = true

            //not valid, so format the error message and stick it in the 'error' variable
            observable.error = exports.formatMessage(ctx.message || rule.message, ctx.params);
            observable.__valid__(false);
            return false;
        } else {
            return true;
        }
    }

    function validateAsync(observable, rule, ctx) {
        observable.isValidating(true);

        var callBack = function (valObj) {
            var isValid = false,
                msg = '';

            if (!observable.__valid__()) {

                // since we're returning early, make sure we turn this off
                observable.isValidating(false);

                return; //if its already NOT valid, don't add to that
            }

            //we were handed back a complex object
            if (valObj['message']) {
                isValid = valObj.isValid;
                msg = valObj.message;
            } else {
                isValid = valObj;
            }

            if (!isValid) {
                //not valid, so format the error message and stick it in the 'error' variable
                observable.error = exports.formatMessage(msg || ctx.message || rule.message, ctx.params);
                observable.__valid__(isValid);
            }

            // tell it that we're done
            observable.isValidating(false);
        };

        //fire the validator and hand it the callback
        rule.validator(observable(), ctx.params || true, callBack);
    }

    validation.validateObservable = function (observable) {
        var i = 0,
            rule, // the rule validator to execute
            ctx, // the current Rule Context for the loop
            ruleContexts = observable.rules(), //cache for iterator
            len = ruleContexts.length; //cache for iterator

        for (; i < len; i++) {

            //get the Rule Context info to give to the core Rule
            ctx = ruleContexts[i];

            // checks an 'onlyIf' condition
            if (ctx.condition && !ctx.condition())
                continue;

            //get the core Rule to use for validation
            rule = exports.rules[ctx.rule];

            if (rule['async'] || ctx['async']) {
                //run async validation
                validateAsync(observable, rule, ctx);

            } else {
                //run normal sync validation
                if (!validateSync(observable, rule, ctx)) {
                    return false; //break out of the loop
                }
            }
        }
        //finally if we got this far, make the observable valid again!
        observable.error = null;
        observable.__valid__(true);
        return true;
    };

    //#endregion

    //#region Validated Observable

    ko.validatedObservable = function (initialValue) {
        if (!exports.utils.isObject(initialValue)) { return ko.observable(initialValue).extend({ validatable: true }); }

        var obsv = ko.observable(initialValue);
        obsv.errors = exports.group(initialValue);
        obsv.isValid = ko.computed(function () {
            return obsv.errors().length === 0;
        });

        return obsv;
    };

    //#endregion

    //#region Localization

    //quick function to override rule messages
    validation.localize = function (msgTranslations) {

        var msg, rule;

        //loop the properties in the object and assign the msg to the rule
        for (rule in msgTranslations) {
            if (exports.rules.hasOwnProperty(rule)) {
                exports.rules[rule].message = msgTranslations[rule];
            }
        }
    };
    //#endregion

    //#region ApplyBindings Added Functionality
    ko.applyBindingsWithValidation = function (viewModel, rootNode, options) {
        var len = arguments.length,
            node, config;

        if (len > 2) { // all parameters were passed
            node = rootNode;
            config = options;
        } else if (len < 2) {
            node = document.body;
        } else { //have to figure out if they passed in a root node or options
            if (arguments[1].nodeType) { //its a node
                node = rootNode;
            } else {
                config = arguments[1];
            }
        }

        exports.init();

        if (config) { exports.utils.setDomData(node, config); }

        ko.applyBindings(viewModel, rootNode);
    };

    //override the original applyBindings so that we can ensure all new rules and what not are correctly registered
    var origApplyBindings = ko.applyBindings;
    ko.applyBindings = function (viewModel, rootNode) {

        exports.init();

        origApplyBindings(viewModel, rootNode);
    };

    //#endregion

    /// apply our public api to the public object
    ko.utils.extend(exports, validation);

}));

},{"knockout":191}],191:[function(require,module,exports){
/*!
 * Knockout JavaScript library v3.4.0
 * (c) Steven Sanderson - http://knockoutjs.com/
 * License: MIT (http://www.opensource.org/licenses/mit-license.php)
 */

(function(){
var DEBUG=true;
(function(undefined){
    // (0, eval)('this') is a robust way of getting a reference to the global object
    // For details, see http://stackoverflow.com/questions/14119988/return-this-0-evalthis/14120023#14120023
    var window = this || (0, eval)('this'),
        document = window['document'],
        navigator = window['navigator'],
        jQueryInstance = window["jQuery"],
        JSON = window["JSON"];
(function(factory) {
    // Support three module loading scenarios
    if (typeof define === 'function' && define['amd']) {
        // [1] AMD anonymous module
        define(['exports', 'require'], factory);
    } else if (typeof exports === 'object' && typeof module === 'object') {
        // [2] CommonJS/Node.js
        factory(module['exports'] || exports);  // module.exports is for Node.js
    } else {
        // [3] No module loader (plain <script> tag) - put directly in global namespace
        factory(window['ko'] = {});
    }
}(function(koExports, amdRequire){
// Internally, all KO objects are attached to koExports (even the non-exported ones whose names will be minified by the closure compiler).
// In the future, the following "ko" variable may be made distinct from "koExports" so that private objects are not externally reachable.
var ko = typeof koExports !== 'undefined' ? koExports : {};
// Google Closure Compiler helpers (used only to make the minified file smaller)
ko.exportSymbol = function(koPath, object) {
    var tokens = koPath.split(".");

    // In the future, "ko" may become distinct from "koExports" (so that non-exported objects are not reachable)
    // At that point, "target" would be set to: (typeof koExports !== "undefined" ? koExports : ko)
    var target = ko;

    for (var i = 0; i < tokens.length - 1; i++)
        target = target[tokens[i]];
    target[tokens[tokens.length - 1]] = object;
};
ko.exportProperty = function(owner, publicName, object) {
    owner[publicName] = object;
};
ko.version = "3.4.0";

ko.exportSymbol('version', ko.version);
// For any options that may affect various areas of Knockout and aren't directly associated with data binding.
ko.options = {
    'deferUpdates': false,
    'useOnlyNativeEvents': false
};

//ko.exportSymbol('options', ko.options);   // 'options' isn't minified
ko.utils = (function () {
    function objectForEach(obj, action) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                action(prop, obj[prop]);
            }
        }
    }

    function extend(target, source) {
        if (source) {
            for(var prop in source) {
                if(source.hasOwnProperty(prop)) {
                    target[prop] = source[prop];
                }
            }
        }
        return target;
    }

    function setPrototypeOf(obj, proto) {
        obj.__proto__ = proto;
        return obj;
    }

    var canSetPrototype = ({ __proto__: [] } instanceof Array);
    var canUseSymbols = !DEBUG && typeof Symbol === 'function';

    // Represent the known event types in a compact way, then at runtime transform it into a hash with event name as key (for fast lookup)
    var knownEvents = {}, knownEventTypesByEventName = {};
    var keyEventTypeName = (navigator && /Firefox\/2/i.test(navigator.userAgent)) ? 'KeyboardEvent' : 'UIEvents';
    knownEvents[keyEventTypeName] = ['keyup', 'keydown', 'keypress'];
    knownEvents['MouseEvents'] = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'];
    objectForEach(knownEvents, function(eventType, knownEventsForType) {
        if (knownEventsForType.length) {
            for (var i = 0, j = knownEventsForType.length; i < j; i++)
                knownEventTypesByEventName[knownEventsForType[i]] = eventType;
        }
    });
    var eventsThatMustBeRegisteredUsingAttachEvent = { 'propertychange': true }; // Workaround for an IE9 issue - https://github.com/SteveSanderson/knockout/issues/406

    // Detect IE versions for bug workarounds (uses IE conditionals, not UA string, for robustness)
    // Note that, since IE 10 does not support conditional comments, the following logic only detects IE < 10.
    // Currently this is by design, since IE 10+ behaves correctly when treated as a standard browser.
    // If there is a future need to detect specific versions of IE10+, we will amend this.
    var ieVersion = document && (function() {
        var version = 3, div = document.createElement('div'), iElems = div.getElementsByTagName('i');

        // Keep constructing conditional HTML blocks until we hit one that resolves to an empty fragment
        while (
            div.innerHTML = '<!--[if gt IE ' + (++version) + ']><i></i><![endif]-->',
            iElems[0]
        ) {}
        return version > 4 ? version : undefined;
    }());
    var isIe6 = ieVersion === 6,
        isIe7 = ieVersion === 7;

    function isClickOnCheckableElement(element, eventType) {
        if ((ko.utils.tagNameLower(element) !== "input") || !element.type) return false;
        if (eventType.toLowerCase() != "click") return false;
        var inputType = element.type;
        return (inputType == "checkbox") || (inputType == "radio");
    }

    // For details on the pattern for changing node classes
    // see: https://github.com/knockout/knockout/issues/1597
    var cssClassNameRegex = /\S+/g;

    function toggleDomNodeCssClass(node, classNames, shouldHaveClass) {
        var addOrRemoveFn;
        if (classNames) {
            if (typeof node.classList === 'object') {
                addOrRemoveFn = node.classList[shouldHaveClass ? 'add' : 'remove'];
                ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
                    addOrRemoveFn.call(node.classList, className);
                });
            } else if (typeof node.className['baseVal'] === 'string') {
                // SVG tag .classNames is an SVGAnimatedString instance
                toggleObjectClassPropertyString(node.className, 'baseVal', classNames, shouldHaveClass);
            } else {
                // node.className ought to be a string.
                toggleObjectClassPropertyString(node, 'className', classNames, shouldHaveClass);
            }
        }
    }

    function toggleObjectClassPropertyString(obj, prop, classNames, shouldHaveClass) {
        // obj/prop is either a node/'className' or a SVGAnimatedString/'baseVal'.
        var currentClassNames = obj[prop].match(cssClassNameRegex) || [];
        ko.utils.arrayForEach(classNames.match(cssClassNameRegex), function(className) {
            ko.utils.addOrRemoveItem(currentClassNames, className, shouldHaveClass);
        });
        obj[prop] = currentClassNames.join(" ");
    }

    return {
        fieldsIncludedWithJsonPost: ['authenticity_token', /^__RequestVerificationToken(_.*)?$/],

        arrayForEach: function (array, action) {
            for (var i = 0, j = array.length; i < j; i++)
                action(array[i], i);
        },

        arrayIndexOf: function (array, item) {
            if (typeof Array.prototype.indexOf == "function")
                return Array.prototype.indexOf.call(array, item);
            for (var i = 0, j = array.length; i < j; i++)
                if (array[i] === item)
                    return i;
            return -1;
        },

        arrayFirst: function (array, predicate, predicateOwner) {
            for (var i = 0, j = array.length; i < j; i++)
                if (predicate.call(predicateOwner, array[i], i))
                    return array[i];
            return null;
        },

        arrayRemoveItem: function (array, itemToRemove) {
            var index = ko.utils.arrayIndexOf(array, itemToRemove);
            if (index > 0) {
                array.splice(index, 1);
            }
            else if (index === 0) {
                array.shift();
            }
        },

        arrayGetDistinctValues: function (array) {
            array = array || [];
            var result = [];
            for (var i = 0, j = array.length; i < j; i++) {
                if (ko.utils.arrayIndexOf(result, array[i]) < 0)
                    result.push(array[i]);
            }
            return result;
        },

        arrayMap: function (array, mapping) {
            array = array || [];
            var result = [];
            for (var i = 0, j = array.length; i < j; i++)
                result.push(mapping(array[i], i));
            return result;
        },

        arrayFilter: function (array, predicate) {
            array = array || [];
            var result = [];
            for (var i = 0, j = array.length; i < j; i++)
                if (predicate(array[i], i))
                    result.push(array[i]);
            return result;
        },

        arrayPushAll: function (array, valuesToPush) {
            if (valuesToPush instanceof Array)
                array.push.apply(array, valuesToPush);
            else
                for (var i = 0, j = valuesToPush.length; i < j; i++)
                    array.push(valuesToPush[i]);
            return array;
        },

        addOrRemoveItem: function(array, value, included) {
            var existingEntryIndex = ko.utils.arrayIndexOf(ko.utils.peekObservable(array), value);
            if (existingEntryIndex < 0) {
                if (included)
                    array.push(value);
            } else {
                if (!included)
                    array.splice(existingEntryIndex, 1);
            }
        },

        canSetPrototype: canSetPrototype,

        extend: extend,

        setPrototypeOf: setPrototypeOf,

        setPrototypeOfOrExtend: canSetPrototype ? setPrototypeOf : extend,

        objectForEach: objectForEach,

        objectMap: function(source, mapping) {
            if (!source)
                return source;
            var target = {};
            for (var prop in source) {
                if (source.hasOwnProperty(prop)) {
                    target[prop] = mapping(source[prop], prop, source);
                }
            }
            return target;
        },

        emptyDomNode: function (domNode) {
            while (domNode.firstChild) {
                ko.removeNode(domNode.firstChild);
            }
        },

        moveCleanedNodesToContainerElement: function(nodes) {
            // Ensure it's a real array, as we're about to reparent the nodes and
            // we don't want the underlying collection to change while we're doing that.
            var nodesArray = ko.utils.makeArray(nodes);
            var templateDocument = (nodesArray[0] && nodesArray[0].ownerDocument) || document;

            var container = templateDocument.createElement('div');
            for (var i = 0, j = nodesArray.length; i < j; i++) {
                container.appendChild(ko.cleanNode(nodesArray[i]));
            }
            return container;
        },

        cloneNodes: function (nodesArray, shouldCleanNodes) {
            for (var i = 0, j = nodesArray.length, newNodesArray = []; i < j; i++) {
                var clonedNode = nodesArray[i].cloneNode(true);
                newNodesArray.push(shouldCleanNodes ? ko.cleanNode(clonedNode) : clonedNode);
            }
            return newNodesArray;
        },

        setDomNodeChildren: function (domNode, childNodes) {
            ko.utils.emptyDomNode(domNode);
            if (childNodes) {
                for (var i = 0, j = childNodes.length; i < j; i++)
                    domNode.appendChild(childNodes[i]);
            }
        },

        replaceDomNodes: function (nodeToReplaceOrNodeArray, newNodesArray) {
            var nodesToReplaceArray = nodeToReplaceOrNodeArray.nodeType ? [nodeToReplaceOrNodeArray] : nodeToReplaceOrNodeArray;
            if (nodesToReplaceArray.length > 0) {
                var insertionPoint = nodesToReplaceArray[0];
                var parent = insertionPoint.parentNode;
                for (var i = 0, j = newNodesArray.length; i < j; i++)
                    parent.insertBefore(newNodesArray[i], insertionPoint);
                for (var i = 0, j = nodesToReplaceArray.length; i < j; i++) {
                    ko.removeNode(nodesToReplaceArray[i]);
                }
            }
        },

        fixUpContinuousNodeArray: function(continuousNodeArray, parentNode) {
            // Before acting on a set of nodes that were previously outputted by a template function, we have to reconcile
            // them against what is in the DOM right now. It may be that some of the nodes have already been removed, or that
            // new nodes might have been inserted in the middle, for example by a binding. Also, there may previously have been
            // leading comment nodes (created by rewritten string-based templates) that have since been removed during binding.
            // So, this function translates the old "map" output array into its best guess of the set of current DOM nodes.
            //
            // Rules:
            //   [A] Any leading nodes that have been removed should be ignored
            //       These most likely correspond to memoization nodes that were already removed during binding
            //       See https://github.com/knockout/knockout/pull/440
            //   [B] Any trailing nodes that have been remove should be ignored
            //       This prevents the code here from adding unrelated nodes to the array while processing rule [C]
            //       See https://github.com/knockout/knockout/pull/1903
            //   [C] We want to output a continuous series of nodes. So, ignore any nodes that have already been removed,
            //       and include any nodes that have been inserted among the previous collection

            if (continuousNodeArray.length) {
                // The parent node can be a virtual element; so get the real parent node
                parentNode = (parentNode.nodeType === 8 && parentNode.parentNode) || parentNode;

                // Rule [A]
                while (continuousNodeArray.length && continuousNodeArray[0].parentNode !== parentNode)
                    continuousNodeArray.splice(0, 1);

                // Rule [B]
                while (continuousNodeArray.length > 1 && continuousNodeArray[continuousNodeArray.length - 1].parentNode !== parentNode)
                    continuousNodeArray.length--;

                // Rule [C]
                if (continuousNodeArray.length > 1) {
                    var current = continuousNodeArray[0], last = continuousNodeArray[continuousNodeArray.length - 1];
                    // Replace with the actual new continuous node set
                    continuousNodeArray.length = 0;
                    while (current !== last) {
                        continuousNodeArray.push(current);
                        current = current.nextSibling;
                    }
                    continuousNodeArray.push(last);
                }
            }
            return continuousNodeArray;
        },

        setOptionNodeSelectionState: function (optionNode, isSelected) {
            // IE6 sometimes throws "unknown error" if you try to write to .selected directly, whereas Firefox struggles with setAttribute. Pick one based on browser.
            if (ieVersion < 7)
                optionNode.setAttribute("selected", isSelected);
            else
                optionNode.selected = isSelected;
        },

        stringTrim: function (string) {
            return string === null || string === undefined ? '' :
                string.trim ?
                    string.trim() :
                    string.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
        },

        stringStartsWith: function (string, startsWith) {
            string = string || "";
            if (startsWith.length > string.length)
                return false;
            return string.substring(0, startsWith.length) === startsWith;
        },

        domNodeIsContainedBy: function (node, containedByNode) {
            if (node === containedByNode)
                return true;
            if (node.nodeType === 11)
                return false; // Fixes issue #1162 - can't use node.contains for document fragments on IE8
            if (containedByNode.contains)
                return containedByNode.contains(node.nodeType === 3 ? node.parentNode : node);
            if (containedByNode.compareDocumentPosition)
                return (containedByNode.compareDocumentPosition(node) & 16) == 16;
            while (node && node != containedByNode) {
                node = node.parentNode;
            }
            return !!node;
        },

        domNodeIsAttachedToDocument: function (node) {
            return ko.utils.domNodeIsContainedBy(node, node.ownerDocument.documentElement);
        },

        anyDomNodeIsAttachedToDocument: function(nodes) {
            return !!ko.utils.arrayFirst(nodes, ko.utils.domNodeIsAttachedToDocument);
        },

        tagNameLower: function(element) {
            // For HTML elements, tagName will always be upper case; for XHTML elements, it'll be lower case.
            // Possible future optimization: If we know it's an element from an XHTML document (not HTML),
            // we don't need to do the .toLowerCase() as it will always be lower case anyway.
            return element && element.tagName && element.tagName.toLowerCase();
        },

        catchFunctionErrors: function (delegate) {
            return ko['onError'] ? function () {
                try {
                    return delegate.apply(this, arguments);
                } catch (e) {
                    ko['onError'] && ko['onError'](e);
                    throw e;
                }
            } : delegate;
        },

        setTimeout: function (handler, timeout) {
            return setTimeout(ko.utils.catchFunctionErrors(handler), timeout);
        },

        deferError: function (error) {
            setTimeout(function () {
                ko['onError'] && ko['onError'](error);
                throw error;
            }, 0);
        },

        registerEventHandler: function (element, eventType, handler) {
            var wrappedHandler = ko.utils.catchFunctionErrors(handler);

            var mustUseAttachEvent = ieVersion && eventsThatMustBeRegisteredUsingAttachEvent[eventType];
            if (!ko.options['useOnlyNativeEvents'] && !mustUseAttachEvent && jQueryInstance) {
                jQueryInstance(element)['bind'](eventType, wrappedHandler);
            } else if (!mustUseAttachEvent && typeof element.addEventListener == "function")
                element.addEventListener(eventType, wrappedHandler, false);
            else if (typeof element.attachEvent != "undefined") {
                var attachEventHandler = function (event) { wrappedHandler.call(element, event); },
                    attachEventName = "on" + eventType;
                element.attachEvent(attachEventName, attachEventHandler);

                // IE does not dispose attachEvent handlers automatically (unlike with addEventListener)
                // so to avoid leaks, we have to remove them manually. See bug #856
                ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                    element.detachEvent(attachEventName, attachEventHandler);
                });
            } else
                throw new Error("Browser doesn't support addEventListener or attachEvent");
        },

        triggerEvent: function (element, eventType) {
            if (!(element && element.nodeType))
                throw new Error("element must be a DOM node when calling triggerEvent");

            // For click events on checkboxes and radio buttons, jQuery toggles the element checked state *after* the
            // event handler runs instead of *before*. (This was fixed in 1.9 for checkboxes but not for radio buttons.)
            // IE doesn't change the checked state when you trigger the click event using "fireEvent".
            // In both cases, we'll use the click method instead.
            var useClickWorkaround = isClickOnCheckableElement(element, eventType);

            if (!ko.options['useOnlyNativeEvents'] && jQueryInstance && !useClickWorkaround) {
                jQueryInstance(element)['trigger'](eventType);
            } else if (typeof document.createEvent == "function") {
                if (typeof element.dispatchEvent == "function") {
                    var eventCategory = knownEventTypesByEventName[eventType] || "HTMLEvents";
                    var event = document.createEvent(eventCategory);
                    event.initEvent(eventType, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, element);
                    element.dispatchEvent(event);
                }
                else
                    throw new Error("The supplied element doesn't support dispatchEvent");
            } else if (useClickWorkaround && element.click) {
                element.click();
            } else if (typeof element.fireEvent != "undefined") {
                element.fireEvent("on" + eventType);
            } else {
                throw new Error("Browser doesn't support triggering events");
            }
        },

        unwrapObservable: function (value) {
            return ko.isObservable(value) ? value() : value;
        },

        peekObservable: function (value) {
            return ko.isObservable(value) ? value.peek() : value;
        },

        toggleDomNodeCssClass: toggleDomNodeCssClass,

        setTextContent: function(element, textContent) {
            var value = ko.utils.unwrapObservable(textContent);
            if ((value === null) || (value === undefined))
                value = "";

            // We need there to be exactly one child: a text node.
            // If there are no children, more than one, or if it's not a text node,
            // we'll clear everything and create a single text node.
            var innerTextNode = ko.virtualElements.firstChild(element);
            if (!innerTextNode || innerTextNode.nodeType != 3 || ko.virtualElements.nextSibling(innerTextNode)) {
                ko.virtualElements.setDomNodeChildren(element, [element.ownerDocument.createTextNode(value)]);
            } else {
                innerTextNode.data = value;
            }

            ko.utils.forceRefresh(element);
        },

        setElementName: function(element, name) {
            element.name = name;

            // Workaround IE 6/7 issue
            // - https://github.com/SteveSanderson/knockout/issues/197
            // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/
            if (ieVersion <= 7) {
                try {
                    element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false);
                }
                catch(e) {} // For IE9 with doc mode "IE9 Standards" and browser mode "IE9 Compatibility View"
            }
        },

        forceRefresh: function(node) {
            // Workaround for an IE9 rendering bug - https://github.com/SteveSanderson/knockout/issues/209
            if (ieVersion >= 9) {
                // For text nodes and comment nodes (most likely virtual elements), we will have to refresh the container
                var elem = node.nodeType == 1 ? node : node.parentNode;
                if (elem.style)
                    elem.style.zoom = elem.style.zoom;
            }
        },

        ensureSelectElementIsRenderedCorrectly: function(selectElement) {
            // Workaround for IE9 rendering bug - it doesn't reliably display all the text in dynamically-added select boxes unless you force it to re-render by updating the width.
            // (See https://github.com/SteveSanderson/knockout/issues/312, http://stackoverflow.com/questions/5908494/select-only-shows-first-char-of-selected-option)
            // Also fixes IE7 and IE8 bug that causes selects to be zero width if enclosed by 'if' or 'with'. (See issue #839)
            if (ieVersion) {
                var originalWidth = selectElement.style.width;
                selectElement.style.width = 0;
                selectElement.style.width = originalWidth;
            }
        },

        range: function (min, max) {
            min = ko.utils.unwrapObservable(min);
            max = ko.utils.unwrapObservable(max);
            var result = [];
            for (var i = min; i <= max; i++)
                result.push(i);
            return result;
        },

        makeArray: function(arrayLikeObject) {
            var result = [];
            for (var i = 0, j = arrayLikeObject.length; i < j; i++) {
                result.push(arrayLikeObject[i]);
            };
            return result;
        },

        createSymbolOrString: function(identifier) {
            return canUseSymbols ? Symbol(identifier) : identifier;
        },

        isIe6 : isIe6,
        isIe7 : isIe7,
        ieVersion : ieVersion,

        getFormFields: function(form, fieldName) {
            var fields = ko.utils.makeArray(form.getElementsByTagName("input")).concat(ko.utils.makeArray(form.getElementsByTagName("textarea")));
            var isMatchingField = (typeof fieldName == 'string')
                ? function(field) { return field.name === fieldName }
                : function(field) { return fieldName.test(field.name) }; // Treat fieldName as regex or object containing predicate
            var matches = [];
            for (var i = fields.length - 1; i >= 0; i--) {
                if (isMatchingField(fields[i]))
                    matches.push(fields[i]);
            };
            return matches;
        },

        parseJson: function (jsonString) {
            if (typeof jsonString == "string") {
                jsonString = ko.utils.stringTrim(jsonString);
                if (jsonString) {
                    if (JSON && JSON.parse) // Use native parsing where available
                        return JSON.parse(jsonString);
                    return (new Function("return " + jsonString))(); // Fallback on less safe parsing for older browsers
                }
            }
            return null;
        },

        stringifyJson: function (data, replacer, space) {   // replacer and space are optional
            if (!JSON || !JSON.stringify)
                throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
            return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
        },

        postJson: function (urlOrForm, data, options) {
            options = options || {};
            var params = options['params'] || {};
            var includeFields = options['includeFields'] || this.fieldsIncludedWithJsonPost;
            var url = urlOrForm;

            // If we were given a form, use its 'action' URL and pick out any requested field values
            if((typeof urlOrForm == 'object') && (ko.utils.tagNameLower(urlOrForm) === "form")) {
                var originalForm = urlOrForm;
                url = originalForm.action;
                for (var i = includeFields.length - 1; i >= 0; i--) {
                    var fields = ko.utils.getFormFields(originalForm, includeFields[i]);
                    for (var j = fields.length - 1; j >= 0; j--)
                        params[fields[j].name] = fields[j].value;
                }
            }

            data = ko.utils.unwrapObservable(data);
            var form = document.createElement("form");
            form.style.display = "none";
            form.action = url;
            form.method = "post";
            for (var key in data) {
                // Since 'data' this is a model object, we include all properties including those inherited from its prototype
                var input = document.createElement("input");
                input.type = "hidden";
                input.name = key;
                input.value = ko.utils.stringifyJson(ko.utils.unwrapObservable(data[key]));
                form.appendChild(input);
            }
            objectForEach(params, function(key, value) {
                var input = document.createElement("input");
                input.type = "hidden";
                input.name = key;
                input.value = value;
                form.appendChild(input);
            });
            document.body.appendChild(form);
            options['submitter'] ? options['submitter'](form) : form.submit();
            setTimeout(function () { form.parentNode.removeChild(form); }, 0);
        }
    }
}());

ko.exportSymbol('utils', ko.utils);
ko.exportSymbol('utils.arrayForEach', ko.utils.arrayForEach);
ko.exportSymbol('utils.arrayFirst', ko.utils.arrayFirst);
ko.exportSymbol('utils.arrayFilter', ko.utils.arrayFilter);
ko.exportSymbol('utils.arrayGetDistinctValues', ko.utils.arrayGetDistinctValues);
ko.exportSymbol('utils.arrayIndexOf', ko.utils.arrayIndexOf);
ko.exportSymbol('utils.arrayMap', ko.utils.arrayMap);
ko.exportSymbol('utils.arrayPushAll', ko.utils.arrayPushAll);
ko.exportSymbol('utils.arrayRemoveItem', ko.utils.arrayRemoveItem);
ko.exportSymbol('utils.extend', ko.utils.extend);
ko.exportSymbol('utils.fieldsIncludedWithJsonPost', ko.utils.fieldsIncludedWithJsonPost);
ko.exportSymbol('utils.getFormFields', ko.utils.getFormFields);
ko.exportSymbol('utils.peekObservable', ko.utils.peekObservable);
ko.exportSymbol('utils.postJson', ko.utils.postJson);
ko.exportSymbol('utils.parseJson', ko.utils.parseJson);
ko.exportSymbol('utils.registerEventHandler', ko.utils.registerEventHandler);
ko.exportSymbol('utils.stringifyJson', ko.utils.stringifyJson);
ko.exportSymbol('utils.range', ko.utils.range);
ko.exportSymbol('utils.toggleDomNodeCssClass', ko.utils.toggleDomNodeCssClass);
ko.exportSymbol('utils.triggerEvent', ko.utils.triggerEvent);
ko.exportSymbol('utils.unwrapObservable', ko.utils.unwrapObservable);
ko.exportSymbol('utils.objectForEach', ko.utils.objectForEach);
ko.exportSymbol('utils.addOrRemoveItem', ko.utils.addOrRemoveItem);
ko.exportSymbol('utils.setTextContent', ko.utils.setTextContent);
ko.exportSymbol('unwrap', ko.utils.unwrapObservable); // Convenient shorthand, because this is used so commonly

if (!Function.prototype['bind']) {
    // Function.prototype.bind is a standard part of ECMAScript 5th Edition (December 2009, http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf)
    // In case the browser doesn't implement it natively, provide a JavaScript implementation. This implementation is based on the one in prototype.js
    Function.prototype['bind'] = function (object) {
        var originalFunction = this;
        if (arguments.length === 1) {
            return function () {
                return originalFunction.apply(object, arguments);
            };
        } else {
            var partialArgs = Array.prototype.slice.call(arguments, 1);
            return function () {
                var args = partialArgs.slice(0);
                args.push.apply(args, arguments);
                return originalFunction.apply(object, args);
            };
        }
    };
}

ko.utils.domData = new (function () {
    var uniqueId = 0;
    var dataStoreKeyExpandoPropertyName = "__ko__" + (new Date).getTime();
    var dataStore = {};

    function getAll(node, createIfNotFound) {
        var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
        var hasExistingDataStore = dataStoreKey && (dataStoreKey !== "null") && dataStore[dataStoreKey];
        if (!hasExistingDataStore) {
            if (!createIfNotFound)
                return undefined;
            dataStoreKey = node[dataStoreKeyExpandoPropertyName] = "ko" + uniqueId++;
            dataStore[dataStoreKey] = {};
        }
        return dataStore[dataStoreKey];
    }

    return {
        get: function (node, key) {
            var allDataForNode = getAll(node, false);
            return allDataForNode === undefined ? undefined : allDataForNode[key];
        },
        set: function (node, key, value) {
            if (value === undefined) {
                // Make sure we don't actually create a new domData key if we are actually deleting a value
                if (getAll(node, false) === undefined)
                    return;
            }
            var allDataForNode = getAll(node, true);
            allDataForNode[key] = value;
        },
        clear: function (node) {
            var dataStoreKey = node[dataStoreKeyExpandoPropertyName];
            if (dataStoreKey) {
                delete dataStore[dataStoreKey];
                node[dataStoreKeyExpandoPropertyName] = null;
                return true; // Exposing "did clean" flag purely so specs can infer whether things have been cleaned up as intended
            }
            return false;
        },

        nextKey: function () {
            return (uniqueId++) + dataStoreKeyExpandoPropertyName;
        }
    };
})();

ko.exportSymbol('utils.domData', ko.utils.domData);
ko.exportSymbol('utils.domData.clear', ko.utils.domData.clear); // Exporting only so specs can clear up after themselves fully

ko.utils.domNodeDisposal = new (function () {
    var domDataKey = ko.utils.domData.nextKey();
    var cleanableNodeTypes = { 1: true, 8: true, 9: true };       // Element, Comment, Document
    var cleanableNodeTypesWithDescendants = { 1: true, 9: true }; // Element, Document

    function getDisposeCallbacksCollection(node, createIfNotFound) {
        var allDisposeCallbacks = ko.utils.domData.get(node, domDataKey);
        if ((allDisposeCallbacks === undefined) && createIfNotFound) {
            allDisposeCallbacks = [];
            ko.utils.domData.set(node, domDataKey, allDisposeCallbacks);
        }
        return allDisposeCallbacks;
    }
    function destroyCallbacksCollection(node) {
        ko.utils.domData.set(node, domDataKey, undefined);
    }

    function cleanSingleNode(node) {
        // Run all the dispose callbacks
        var callbacks = getDisposeCallbacksCollection(node, false);
        if (callbacks) {
            callbacks = callbacks.slice(0); // Clone, as the array may be modified during iteration (typically, callbacks will remove themselves)
            for (var i = 0; i < callbacks.length; i++)
                callbacks[i](node);
        }

        // Erase the DOM data
        ko.utils.domData.clear(node);

        // Perform cleanup needed by external libraries (currently only jQuery, but can be extended)
        ko.utils.domNodeDisposal["cleanExternalData"](node);

        // Clear any immediate-child comment nodes, as these wouldn't have been found by
        // node.getElementsByTagName("*") in cleanNode() (comment nodes aren't elements)
        if (cleanableNodeTypesWithDescendants[node.nodeType])
            cleanImmediateCommentTypeChildren(node);
    }

    function cleanImmediateCommentTypeChildren(nodeWithChildren) {
        var child, nextChild = nodeWithChildren.firstChild;
        while (child = nextChild) {
            nextChild = child.nextSibling;
            if (child.nodeType === 8)
                cleanSingleNode(child);
        }
    }

    return {
        addDisposeCallback : function(node, callback) {
            if (typeof callback != "function")
                throw new Error("Callback must be a function");
            getDisposeCallbacksCollection(node, true).push(callback);
        },

        removeDisposeCallback : function(node, callback) {
            var callbacksCollection = getDisposeCallbacksCollection(node, false);
            if (callbacksCollection) {
                ko.utils.arrayRemoveItem(callbacksCollection, callback);
                if (callbacksCollection.length == 0)
                    destroyCallbacksCollection(node);
            }
        },

        cleanNode : function(node) {
            // First clean this node, where applicable
            if (cleanableNodeTypes[node.nodeType]) {
                cleanSingleNode(node);

                // ... then its descendants, where applicable
                if (cleanableNodeTypesWithDescendants[node.nodeType]) {
                    // Clone the descendants list in case it changes during iteration
                    var descendants = [];
                    ko.utils.arrayPushAll(descendants, node.getElementsByTagName("*"));
                    for (var i = 0, j = descendants.length; i < j; i++)
                        cleanSingleNode(descendants[i]);
                }
            }
            return node;
        },

        removeNode : function(node) {
            ko.cleanNode(node);
            if (node.parentNode)
                node.parentNode.removeChild(node);
        },

        "cleanExternalData" : function (node) {
            // Special support for jQuery here because it's so commonly used.
            // Many jQuery plugins (including jquery.tmpl) store data using jQuery's equivalent of domData
            // so notify it to tear down any resources associated with the node & descendants here.
            if (jQueryInstance && (typeof jQueryInstance['cleanData'] == "function"))
                jQueryInstance['cleanData']([node]);
        }
    };
})();
ko.cleanNode = ko.utils.domNodeDisposal.cleanNode; // Shorthand name for convenience
ko.removeNode = ko.utils.domNodeDisposal.removeNode; // Shorthand name for convenience
ko.exportSymbol('cleanNode', ko.cleanNode);
ko.exportSymbol('removeNode', ko.removeNode);
ko.exportSymbol('utils.domNodeDisposal', ko.utils.domNodeDisposal);
ko.exportSymbol('utils.domNodeDisposal.addDisposeCallback', ko.utils.domNodeDisposal.addDisposeCallback);
ko.exportSymbol('utils.domNodeDisposal.removeDisposeCallback', ko.utils.domNodeDisposal.removeDisposeCallback);
(function () {
    var none = [0, "", ""],
        table = [1, "<table>", "</table>"],
        tbody = [2, "<table><tbody>", "</tbody></table>"],
        tr = [3, "<table><tbody><tr>", "</tr></tbody></table>"],
        select = [1, "<select multiple='multiple'>", "</select>"],
        lookup = {
            'thead': table,
            'tbody': table,
            'tfoot': table,
            'tr': tbody,
            'td': tr,
            'th': tr,
            'option': select,
            'optgroup': select
        },

        // This is needed for old IE if you're *not* using either jQuery or innerShiv. Doesn't affect other cases.
        mayRequireCreateElementHack = ko.utils.ieVersion <= 8;

    function getWrap(tags) {
        var m = tags.match(/^<([a-z]+)[ >]/);
        return (m && lookup[m[1]]) || none;
    }

    function simpleHtmlParse(html, documentContext) {
        documentContext || (documentContext = document);
        var windowContext = documentContext['parentWindow'] || documentContext['defaultView'] || window;

        // Based on jQuery's "clean" function, but only accounting for table-related elements.
        // If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly

        // Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
        // a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
        // This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
        // (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.

        // Trim whitespace, otherwise indexOf won't work as expected
        var tags = ko.utils.stringTrim(html).toLowerCase(), div = documentContext.createElement("div"),
            wrap = getWrap(tags),
            depth = wrap[0];

        // Go to html and back, then peel off extra wrappers
        // Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
        var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
        if (typeof windowContext['innerShiv'] == "function") {
            // Note that innerShiv is deprecated in favour of html5shiv. We should consider adding
            // support for html5shiv (except if no explicit support is needed, e.g., if html5shiv
            // somehow shims the native APIs so it just works anyway)
            div.appendChild(windowContext['innerShiv'](markup));
        } else {
            if (mayRequireCreateElementHack) {
                // The document.createElement('my-element') trick to enable custom elements in IE6-8
                // only works if we assign innerHTML on an element associated with that document.
                documentContext.appendChild(div);
            }

            div.innerHTML = markup;

            if (mayRequireCreateElementHack) {
                div.parentNode.removeChild(div);
            }
        }

        // Move to the right depth
        while (depth--)
            div = div.lastChild;

        return ko.utils.makeArray(div.lastChild.childNodes);
    }

    function jQueryHtmlParse(html, documentContext) {
        // jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
        if (jQueryInstance['parseHTML']) {
            return jQueryInstance['parseHTML'](html, documentContext) || []; // Ensure we always return an array and never null
        } else {
            // For jQuery < 1.8.0, we fall back on the undocumented internal "clean" function.
            var elems = jQueryInstance['clean']([html], documentContext);

            // As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
            // Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
            // Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
            if (elems && elems[0]) {
                // Find the top-most parent element that's a direct child of a document fragment
                var elem = elems[0];
                while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
                    elem = elem.parentNode;
                // ... then detach it
                if (elem.parentNode)
                    elem.parentNode.removeChild(elem);
            }

            return elems;
        }
    }

    ko.utils.parseHtmlFragment = function(html, documentContext) {
        return jQueryInstance ?
            jQueryHtmlParse(html, documentContext) :   // As below, benefit from jQuery's optimisations where possible
            simpleHtmlParse(html, documentContext);  // ... otherwise, this simple logic will do in most common cases.
    };

    ko.utils.setHtml = function(node, html) {
        ko.utils.emptyDomNode(node);

        // There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
        html = ko.utils.unwrapObservable(html);

        if ((html !== null) && (html !== undefined)) {
            if (typeof html != 'string')
                html = html.toString();

            // jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
            // for example <tr> elements which are not normally allowed to exist on their own.
            // If you've referenced jQuery we'll use that rather than duplicating its code.
            if (jQueryInstance) {
                jQueryInstance(node)['html'](html);
            } else {
                // ... otherwise, use KO's own parsing logic.
                var parsedNodes = ko.utils.parseHtmlFragment(html, node.ownerDocument);
                for (var i = 0; i < parsedNodes.length; i++)
                    node.appendChild(parsedNodes[i]);
            }
        }
    };
})();

ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
ko.exportSymbol('utils.setHtml', ko.utils.setHtml);

ko.memoization = (function () {
    var memos = {};

    function randomMax8HexChars() {
        return (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1);
    }
    function generateRandomId() {
        return randomMax8HexChars() + randomMax8HexChars();
    }
    function findMemoNodes(rootNode, appendToArray) {
        if (!rootNode)
            return;
        if (rootNode.nodeType == 8) {
            var memoId = ko.memoization.parseMemoText(rootNode.nodeValue);
            if (memoId != null)
                appendToArray.push({ domNode: rootNode, memoId: memoId });
        } else if (rootNode.nodeType == 1) {
            for (var i = 0, childNodes = rootNode.childNodes, j = childNodes.length; i < j; i++)
                findMemoNodes(childNodes[i], appendToArray);
        }
    }

    return {
        memoize: function (callback) {
            if (typeof callback != "function")
                throw new Error("You can only pass a function to ko.memoization.memoize()");
            var memoId = generateRandomId();
            memos[memoId] = callback;
            return "<!--[ko_memo:" + memoId + "]-->";
        },

        unmemoize: function (memoId, callbackParams) {
            var callback = memos[memoId];
            if (callback === undefined)
                throw new Error("Couldn't find any memo with ID " + memoId + ". Perhaps it's already been unmemoized.");
            try {
                callback.apply(null, callbackParams || []);
                return true;
            }
            finally { delete memos[memoId]; }
        },

        unmemoizeDomNodeAndDescendants: function (domNode, extraCallbackParamsArray) {
            var memos = [];
            findMemoNodes(domNode, memos);
            for (var i = 0, j = memos.length; i < j; i++) {
                var node = memos[i].domNode;
                var combinedParams = [node];
                if (extraCallbackParamsArray)
                    ko.utils.arrayPushAll(combinedParams, extraCallbackParamsArray);
                ko.memoization.unmemoize(memos[i].memoId, combinedParams);
                node.nodeValue = ""; // Neuter this node so we don't try to unmemoize it again
                if (node.parentNode)
                    node.parentNode.removeChild(node); // If possible, erase it totally (not always possible - someone else might just hold a reference to it then call unmemoizeDomNodeAndDescendants again)
            }
        },

        parseMemoText: function (memoText) {
            var match = memoText.match(/^\[ko_memo\:(.*?)\]$/);
            return match ? match[1] : null;
        }
    };
})();

ko.exportSymbol('memoization', ko.memoization);
ko.exportSymbol('memoization.memoize', ko.memoization.memoize);
ko.exportSymbol('memoization.unmemoize', ko.memoization.unmemoize);
ko.exportSymbol('memoization.parseMemoText', ko.memoization.parseMemoText);
ko.exportSymbol('memoization.unmemoizeDomNodeAndDescendants', ko.memoization.unmemoizeDomNodeAndDescendants);
ko.tasks = (function () {
    var scheduler,
        taskQueue = [],
        taskQueueLength = 0,
        nextHandle = 1,
        nextIndexToProcess = 0;

    if (window['MutationObserver']) {
        // Chrome 27+, Firefox 14+, IE 11+, Opera 15+, Safari 6.1+
        // From https://github.com/petkaantonov/bluebird * Copyright (c) 2014 Petka Antonov * License: MIT
        scheduler = (function (callback) {
            var div = document.createElement("div");
            new MutationObserver(callback).observe(div, {attributes: true});
            return function () { div.classList.toggle("foo"); };
        })(scheduledProcess);
    } else if (document && "onreadystatechange" in document.createElement("script")) {
        // IE 6-10
        // From https://github.com/YuzuJS/setImmediate * Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola * License: MIT
        scheduler = function (callback) {
            var script = document.createElement("script");
            script.onreadystatechange = function () {
                script.onreadystatechange = null;
                document.documentElement.removeChild(script);
                script = null;
                callback();
            };
            document.documentElement.appendChild(script);
        };
    } else {
        scheduler = function (callback) {
            setTimeout(callback, 0);
        };
    }

    function processTasks() {
        if (taskQueueLength) {
            // Each mark represents the end of a logical group of tasks and the number of these groups is
            // limited to prevent unchecked recursion.
            var mark = taskQueueLength, countMarks = 0;

            // nextIndexToProcess keeps track of where we are in the queue; processTasks can be called recursively without issue
            for (var task; nextIndexToProcess < taskQueueLength; ) {
                if (task = taskQueue[nextIndexToProcess++]) {
                    if (nextIndexToProcess > mark) {
                        if (++countMarks >= 5000) {
                            nextIndexToProcess = taskQueueLength;   // skip all tasks remaining in the queue since any of them could be causing the recursion
                            ko.utils.deferError(Error("'Too much recursion' after processing " + countMarks + " task groups."));
                            break;
                        }
                        mark = taskQueueLength;
                    }
                    try {
                        task();
                    } catch (ex) {
                        ko.utils.deferError(ex);
                    }
                }
            }
        }
    }

    function scheduledProcess() {
        processTasks();

        // Reset the queue
        nextIndexToProcess = taskQueueLength = taskQueue.length = 0;
    }

    function scheduleTaskProcessing() {
        ko.tasks['scheduler'](scheduledProcess);
    }

    var tasks = {
        'scheduler': scheduler,     // Allow overriding the scheduler

        schedule: function (func) {
            if (!taskQueueLength) {
                scheduleTaskProcessing();
            }

            taskQueue[taskQueueLength++] = func;
            return nextHandle++;
        },

        cancel: function (handle) {
            var index = handle - (nextHandle - taskQueueLength);
            if (index >= nextIndexToProcess && index < taskQueueLength) {
                taskQueue[index] = null;
            }
        },

        // For testing only: reset the queue and return the previous queue length
        'resetForTesting': function () {
            var length = taskQueueLength - nextIndexToProcess;
            nextIndexToProcess = taskQueueLength = taskQueue.length = 0;
            return length;
        },

        runEarly: processTasks
    };

    return tasks;
})();

ko.exportSymbol('tasks', ko.tasks);
ko.exportSymbol('tasks.schedule', ko.tasks.schedule);
//ko.exportSymbol('tasks.cancel', ko.tasks.cancel);  "cancel" isn't minified
ko.exportSymbol('tasks.runEarly', ko.tasks.runEarly);
ko.extenders = {
    'throttle': function(target, timeout) {
        // Throttling means two things:

        // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
        //     notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
        target['throttleEvaluation'] = timeout;

        // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
        //     so the target cannot change value synchronously or faster than a certain rate
        var writeTimeoutInstance = null;
        return ko.dependentObservable({
            'read': target,
            'write': function(value) {
                clearTimeout(writeTimeoutInstance);
                writeTimeoutInstance = ko.utils.setTimeout(function() {
                    target(value);
                }, timeout);
            }
        });
    },

    'rateLimit': function(target, options) {
        var timeout, method, limitFunction;

        if (typeof options == 'number') {
            timeout = options;
        } else {
            timeout = options['timeout'];
            method = options['method'];
        }

        // rateLimit supersedes deferred updates
        target._deferUpdates = false;

        limitFunction = method == 'notifyWhenChangesStop' ?  debounce : throttle;
        target.limit(function(callback) {
            return limitFunction(callback, timeout);
        });
    },

    'deferred': function(target, options) {
        if (options !== true) {
            throw new Error('The \'deferred\' extender only accepts the value \'true\', because it is not supported to turn deferral off once enabled.')
        }

        if (!target._deferUpdates) {
            target._deferUpdates = true;
            target.limit(function (callback) {
                var handle;
                return function () {
                    ko.tasks.cancel(handle);
                    handle = ko.tasks.schedule(callback);
                    target['notifySubscribers'](undefined, 'dirty');
                };
            });
        }
    },

    'notify': function(target, notifyWhen) {
        target["equalityComparer"] = notifyWhen == "always" ?
            null :  // null equalityComparer means to always notify
            valuesArePrimitiveAndEqual;
    }
};

var primitiveTypes = { 'undefined':1, 'boolean':1, 'number':1, 'string':1 };
function valuesArePrimitiveAndEqual(a, b) {
    var oldValueIsPrimitive = (a === null) || (typeof(a) in primitiveTypes);
    return oldValueIsPrimitive ? (a === b) : false;
}

function throttle(callback, timeout) {
    var timeoutInstance;
    return function () {
        if (!timeoutInstance) {
            timeoutInstance = ko.utils.setTimeout(function () {
                timeoutInstance = undefined;
                callback();
            }, timeout);
        }
    };
}

function debounce(callback, timeout) {
    var timeoutInstance;
    return function () {
        clearTimeout(timeoutInstance);
        timeoutInstance = ko.utils.setTimeout(callback, timeout);
    };
}

function applyExtenders(requestedExtenders) {
    var target = this;
    if (requestedExtenders) {
        ko.utils.objectForEach(requestedExtenders, function(key, value) {
            var extenderHandler = ko.extenders[key];
            if (typeof extenderHandler == 'function') {
                target = extenderHandler(target, value) || target;
            }
        });
    }
    return target;
}

ko.exportSymbol('extenders', ko.extenders);

ko.subscription = function (target, callback, disposeCallback) {
    this._target = target;
    this.callback = callback;
    this.disposeCallback = disposeCallback;
    this.isDisposed = false;
    ko.exportProperty(this, 'dispose', this.dispose);
};
ko.subscription.prototype.dispose = function () {
    this.isDisposed = true;
    this.disposeCallback();
};

ko.subscribable = function () {
    ko.utils.setPrototypeOfOrExtend(this, ko_subscribable_fn);
    ko_subscribable_fn.init(this);
}

var defaultEvent = "change";

// Moved out of "limit" to avoid the extra closure
function limitNotifySubscribers(value, event) {
    if (!event || event === defaultEvent) {
        this._limitChange(value);
    } else if (event === 'beforeChange') {
        this._limitBeforeChange(value);
    } else {
        this._origNotifySubscribers(value, event);
    }
}

var ko_subscribable_fn = {
    init: function(instance) {
        instance._subscriptions = {};
        instance._versionNumber = 1;
    },

    subscribe: function (callback, callbackTarget, event) {
        var self = this;

        event = event || defaultEvent;
        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;

        var subscription = new ko.subscription(self, boundCallback, function () {
            ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
            if (self.afterSubscriptionRemove)
                self.afterSubscriptionRemove(event);
        });

        if (self.beforeSubscriptionAdd)
            self.beforeSubscriptionAdd(event);

        if (!self._subscriptions[event])
            self._subscriptions[event] = [];
        self._subscriptions[event].push(subscription);

        return subscription;
    },

    "notifySubscribers": function (valueToNotify, event) {
        event = event || defaultEvent;
        if (event === defaultEvent) {
            this.updateVersion();
        }
        if (this.hasSubscriptionsForEvent(event)) {
            try {
                ko.dependencyDetection.begin(); // Begin suppressing dependency detection (by setting the top frame to undefined)
                for (var a = this._subscriptions[event].slice(0), i = 0, subscription; subscription = a[i]; ++i) {
                    // In case a subscription was disposed during the arrayForEach cycle, check
                    // for isDisposed on each subscription before invoking its callback
                    if (!subscription.isDisposed)
                        subscription.callback(valueToNotify);
                }
            } finally {
                ko.dependencyDetection.end(); // End suppressing dependency detection
            }
        }
    },

    getVersion: function () {
        return this._versionNumber;
    },

    hasChanged: function (versionToCheck) {
        return this.getVersion() !== versionToCheck;
    },

    updateVersion: function () {
        ++this._versionNumber;
    },

    limit: function(limitFunction) {
        var self = this, selfIsObservable = ko.isObservable(self),
            ignoreBeforeChange, previousValue, pendingValue, beforeChange = 'beforeChange';

        if (!self._origNotifySubscribers) {
            self._origNotifySubscribers = self["notifySubscribers"];
            self["notifySubscribers"] = limitNotifySubscribers;
        }

        var finish = limitFunction(function() {
            self._notificationIsPending = false;

            // If an observable provided a reference to itself, access it to get the latest value.
            // This allows computed observables to delay calculating their value until needed.
            if (selfIsObservable && pendingValue === self) {
                pendingValue = self();
            }
            ignoreBeforeChange = false;
            if (self.isDifferent(previousValue, pendingValue)) {
                self._origNotifySubscribers(previousValue = pendingValue);
            }
        });

        self._limitChange = function(value) {
            self._notificationIsPending = ignoreBeforeChange = true;
            pendingValue = value;
            finish();
        };
        self._limitBeforeChange = function(value) {
            if (!ignoreBeforeChange) {
                previousValue = value;
                self._origNotifySubscribers(value, beforeChange);
            }
        };
    },

    hasSubscriptionsForEvent: function(event) {
        return this._subscriptions[event] && this._subscriptions[event].length;
    },

    getSubscriptionsCount: function (event) {
        if (event) {
            return this._subscriptions[event] && this._subscriptions[event].length || 0;
        } else {
            var total = 0;
            ko.utils.objectForEach(this._subscriptions, function(eventName, subscriptions) {
                if (eventName !== 'dirty')
                    total += subscriptions.length;
            });
            return total;
        }
    },

    isDifferent: function(oldValue, newValue) {
        return !this['equalityComparer'] || !this['equalityComparer'](oldValue, newValue);
    },

    extend: applyExtenders
};

ko.exportProperty(ko_subscribable_fn, 'subscribe', ko_subscribable_fn.subscribe);
ko.exportProperty(ko_subscribable_fn, 'extend', ko_subscribable_fn.extend);
ko.exportProperty(ko_subscribable_fn, 'getSubscriptionsCount', ko_subscribable_fn.getSubscriptionsCount);

// For browsers that support proto assignment, we overwrite the prototype of each
// observable instance. Since observables are functions, we need Function.prototype
// to still be in the prototype chain.
if (ko.utils.canSetPrototype) {
    ko.utils.setPrototypeOf(ko_subscribable_fn, Function.prototype);
}

ko.subscribable['fn'] = ko_subscribable_fn;


ko.isSubscribable = function (instance) {
    return instance != null && typeof instance.subscribe == "function" && typeof instance["notifySubscribers"] == "function";
};

ko.exportSymbol('subscribable', ko.subscribable);
ko.exportSymbol('isSubscribable', ko.isSubscribable);

ko.computedContext = ko.dependencyDetection = (function () {
    var outerFrames = [],
        currentFrame,
        lastId = 0;

    // Return a unique ID that can be assigned to an observable for dependency tracking.
    // Theoretically, you could eventually overflow the number storage size, resulting
    // in duplicate IDs. But in JavaScript, the largest exact integral value is 2^53
    // or 9,007,199,254,740,992. If you created 1,000,000 IDs per second, it would
    // take over 285 years to reach that number.
    // Reference http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
    function getId() {
        return ++lastId;
    }

    function begin(options) {
        outerFrames.push(currentFrame);
        currentFrame = options;
    }

    function end() {
        currentFrame = outerFrames.pop();
    }

    return {
        begin: begin,

        end: end,

        registerDependency: function (subscribable) {
            if (currentFrame) {
                if (!ko.isSubscribable(subscribable))
                    throw new Error("Only subscribable things can act as dependencies");
                currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));
            }
        },

        ignore: function (callback, callbackTarget, callbackArgs) {
            try {
                begin();
                return callback.apply(callbackTarget, callbackArgs || []);
            } finally {
                end();
            }
        },

        getDependenciesCount: function () {
            if (currentFrame)
                return currentFrame.computed.getDependenciesCount();
        },

        isInitial: function() {
            if (currentFrame)
                return currentFrame.isInitial;
        }
    };
})();

ko.exportSymbol('computedContext', ko.computedContext);
ko.exportSymbol('computedContext.getDependenciesCount', ko.computedContext.getDependenciesCount);
ko.exportSymbol('computedContext.isInitial', ko.computedContext.isInitial);

ko.exportSymbol('ignoreDependencies', ko.ignoreDependencies = ko.dependencyDetection.ignore);
var observableLatestValue = ko.utils.createSymbolOrString('_latestValue');

ko.observable = function (initialValue) {
    function observable() {
        if (arguments.length > 0) {
            // Write

            // Ignore writes if the value hasn't changed
            if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {
                observable.valueWillMutate();
                observable[observableLatestValue] = arguments[0];
                observable.valueHasMutated();
            }
            return this; // Permits chained assignments
        }
        else {
            // Read
            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation
            return observable[observableLatestValue];
        }
    }

    observable[observableLatestValue] = initialValue;

    // Inherit from 'subscribable'
    if (!ko.utils.canSetPrototype) {
        // 'subscribable' won't be on the prototype chain unless we put it there directly
        ko.utils.extend(observable, ko.subscribable['fn']);
    }
    ko.subscribable['fn'].init(observable);

    // Inherit from 'observable'
    ko.utils.setPrototypeOfOrExtend(observable, observableFn);

    if (ko.options['deferUpdates']) {
        ko.extenders['deferred'](observable, true);
    }

    return observable;
}

// Define prototype for observables
var observableFn = {
    'equalityComparer': valuesArePrimitiveAndEqual,
    peek: function() { return this[observableLatestValue]; },
    valueHasMutated: function () { this['notifySubscribers'](this[observableLatestValue]); },
    valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }
};

// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the ko.observable constructor
if (ko.utils.canSetPrototype) {
    ko.utils.setPrototypeOf(observableFn, ko.subscribable['fn']);
}

var protoProperty = ko.observable.protoProperty = '__ko_proto__';
observableFn[protoProperty] = ko.observable;

ko.hasPrototype = function(instance, prototype) {
    if ((instance === null) || (instance === undefined) || (instance[protoProperty] === undefined)) return false;
    if (instance[protoProperty] === prototype) return true;
    return ko.hasPrototype(instance[protoProperty], prototype); // Walk the prototype chain
};

ko.isObservable = function (instance) {
    return ko.hasPrototype(instance, ko.observable);
}
ko.isWriteableObservable = function (instance) {
    // Observable
    if ((typeof instance == 'function') && instance[protoProperty] === ko.observable)
        return true;
    // Writeable dependent observable
    if ((typeof instance == 'function') && (instance[protoProperty] === ko.dependentObservable) && (instance.hasWriteFunction))
        return true;
    // Anything else
    return false;
}

ko.exportSymbol('observable', ko.observable);
ko.exportSymbol('isObservable', ko.isObservable);
ko.exportSymbol('isWriteableObservable', ko.isWriteableObservable);
ko.exportSymbol('isWritableObservable', ko.isWriteableObservable);
ko.exportSymbol('observable.fn', observableFn);
ko.exportProperty(observableFn, 'peek', observableFn.peek);
ko.exportProperty(observableFn, 'valueHasMutated', observableFn.valueHasMutated);
ko.exportProperty(observableFn, 'valueWillMutate', observableFn.valueWillMutate);
ko.observableArray = function (initialValues) {
    initialValues = initialValues || [];

    if (typeof initialValues != 'object' || !('length' in initialValues))
        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");

    var result = ko.observable(initialValues);
    ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
    return result.extend({'trackArrayChanges':true});
};

ko.observableArray['fn'] = {
    'remove': function (valueOrPredicate) {
        var underlyingArray = this.peek();
        var removedValues = [];
        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
        for (var i = 0; i < underlyingArray.length; i++) {
            var value = underlyingArray[i];
            if (predicate(value)) {
                if (removedValues.length === 0) {
                    this.valueWillMutate();
                }
                removedValues.push(value);
                underlyingArray.splice(i, 1);
                i--;
            }
        }
        if (removedValues.length) {
            this.valueHasMutated();
        }
        return removedValues;
    },

    'removeAll': function (arrayOfValues) {
        // If you passed zero args, we remove everything
        if (arrayOfValues === undefined) {
            var underlyingArray = this.peek();
            var allValues = underlyingArray.slice(0);
            this.valueWillMutate();
            underlyingArray.splice(0, underlyingArray.length);
            this.valueHasMutated();
            return allValues;
        }
        // If you passed an arg, we interpret it as an array of entries to remove
        if (!arrayOfValues)
            return [];
        return this['remove'](function (value) {
            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
        });
    },

    'destroy': function (valueOrPredicate) {
        var underlyingArray = this.peek();
        var predicate = typeof valueOrPredicate == "function" && !ko.isObservable(valueOrPredicate) ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
        this.valueWillMutate();
        for (var i = underlyingArray.length - 1; i >= 0; i--) {
            var value = underlyingArray[i];
            if (predicate(value))
                underlyingArray[i]["_destroy"] = true;
        }
        this.valueHasMutated();
    },

    'destroyAll': function (arrayOfValues) {
        // If you passed zero args, we destroy everything
        if (arrayOfValues === undefined)
            return this['destroy'](function() { return true });

        // If you passed an arg, we interpret it as an array of entries to destroy
        if (!arrayOfValues)
            return [];
        return this['destroy'](function (value) {
            return ko.utils.arrayIndexOf(arrayOfValues, value) >= 0;
        });
    },

    'indexOf': function (item) {
        var underlyingArray = this();
        return ko.utils.arrayIndexOf(underlyingArray, item);
    },

    'replace': function(oldItem, newItem) {
        var index = this['indexOf'](oldItem);
        if (index >= 0) {
            this.valueWillMutate();
            this.peek()[index] = newItem;
            this.valueHasMutated();
        }
    }
};

// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the ko.observableArray constructor
if (ko.utils.canSetPrototype) {
    ko.utils.setPrototypeOf(ko.observableArray['fn'], ko.observable['fn']);
}

// Populate ko.observableArray.fn with read/write functions from native arrays
// Important: Do not add any additional functions here that may reasonably be used to *read* data from the array
// because we'll eval them without causing subscriptions, so ko.computed output could end up getting stale
ko.utils.arrayForEach(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (methodName) {
    ko.observableArray['fn'][methodName] = function () {
        // Use "peek" to avoid creating a subscription in any computed that we're executing in the context of
        // (for consistency with mutating regular observables)
        var underlyingArray = this.peek();
        this.valueWillMutate();
        this.cacheDiffForKnownOperation(underlyingArray, methodName, arguments);
        var methodCallResult = underlyingArray[methodName].apply(underlyingArray, arguments);
        this.valueHasMutated();
        // The native sort and reverse methods return a reference to the array, but it makes more sense to return the observable array instead.
        return methodCallResult === underlyingArray ? this : methodCallResult;
    };
});

// Populate ko.observableArray.fn with read-only functions from native arrays
ko.utils.arrayForEach(["slice"], function (methodName) {
    ko.observableArray['fn'][methodName] = function () {
        var underlyingArray = this();
        return underlyingArray[methodName].apply(underlyingArray, arguments);
    };
});

ko.exportSymbol('observableArray', ko.observableArray);
var arrayChangeEventName = 'arrayChange';
ko.extenders['trackArrayChanges'] = function(target, options) {
    // Use the provided options--each call to trackArrayChanges overwrites the previously set options
    target.compareArrayOptions = {};
    if (options && typeof options == "object") {
        ko.utils.extend(target.compareArrayOptions, options);
    }
    target.compareArrayOptions['sparse'] = true;

    // Only modify the target observable once
    if (target.cacheDiffForKnownOperation) {
        return;
    }
    var trackingChanges = false,
        cachedDiff = null,
        arrayChangeSubscription,
        pendingNotifications = 0,
        underlyingBeforeSubscriptionAddFunction = target.beforeSubscriptionAdd,
        underlyingAfterSubscriptionRemoveFunction = target.afterSubscriptionRemove;

    // Watch "subscribe" calls, and for array change events, ensure change tracking is enabled
    target.beforeSubscriptionAdd = function (event) {
        if (underlyingBeforeSubscriptionAddFunction)
            underlyingBeforeSubscriptionAddFunction.call(target, event);
        if (event === arrayChangeEventName) {
            trackChanges();
        }
    };
    // Watch "dispose" calls, and for array change events, ensure change tracking is disabled when all are disposed
    target.afterSubscriptionRemove = function (event) {
        if (underlyingAfterSubscriptionRemoveFunction)
            underlyingAfterSubscriptionRemoveFunction.call(target, event);
        if (event === arrayChangeEventName && !target.hasSubscriptionsForEvent(arrayChangeEventName)) {
            arrayChangeSubscription.dispose();
            trackingChanges = false;
        }
    };

    function trackChanges() {
        // Calling 'trackChanges' multiple times is the same as calling it once
        if (trackingChanges) {
            return;
        }

        trackingChanges = true;

        // Intercept "notifySubscribers" to track how many times it was called.
        var underlyingNotifySubscribersFunction = target['notifySubscribers'];
        target['notifySubscribers'] = function(valueToNotify, event) {
            if (!event || event === defaultEvent) {
                ++pendingNotifications;
            }
            return underlyingNotifySubscribersFunction.apply(this, arguments);
        };

        // Each time the array changes value, capture a clone so that on the next
        // change it's possible to produce a diff
        var previousContents = [].concat(target.peek() || []);
        cachedDiff = null;
        arrayChangeSubscription = target.subscribe(function(currentContents) {
            // Make a copy of the current contents and ensure it's an array
            currentContents = [].concat(currentContents || []);

            // Compute the diff and issue notifications, but only if someone is listening
            if (target.hasSubscriptionsForEvent(arrayChangeEventName)) {
                var changes = getChanges(previousContents, currentContents);
            }

            // Eliminate references to the old, removed items, so they can be GCed
            previousContents = currentContents;
            cachedDiff = null;
            pendingNotifications = 0;

            if (changes && changes.length) {
                target['notifySubscribers'](changes, arrayChangeEventName);
            }
        });
    }

    function getChanges(previousContents, currentContents) {
        // We try to re-use cached diffs.
        // The scenarios where pendingNotifications > 1 are when using rate-limiting or the Deferred Updates
        // plugin, which without this check would not be compatible with arrayChange notifications. Normally,
        // notifications are issued immediately so we wouldn't be queueing up more than one.
        if (!cachedDiff || pendingNotifications > 1) {
            cachedDiff = ko.utils.compareArrays(previousContents, currentContents, target.compareArrayOptions);
        }

        return cachedDiff;
    }

    target.cacheDiffForKnownOperation = function(rawArray, operationName, args) {
        // Only run if we're currently tracking changes for this observable array
        // and there aren't any pending deferred notifications.
        if (!trackingChanges || pendingNotifications) {
            return;
        }
        var diff = [],
            arrayLength = rawArray.length,
            argsLength = args.length,
            offset = 0;

        function pushDiff(status, value, index) {
            return diff[diff.length] = { 'status': status, 'value': value, 'index': index };
        }
        switch (operationName) {
            case 'push':
                offset = arrayLength;
            case 'unshift':
                for (var index = 0; index < argsLength; index++) {
                    pushDiff('added', args[index], offset + index);
                }
                break;

            case 'pop':
                offset = arrayLength - 1;
            case 'shift':
                if (arrayLength) {
                    pushDiff('deleted', rawArray[offset], offset);
                }
                break;

            case 'splice':
                // Negative start index means 'from end of array'. After that we clamp to [0...arrayLength].
                // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
                var startIndex = Math.min(Math.max(0, args[0] < 0 ? arrayLength + args[0] : args[0]), arrayLength),
                    endDeleteIndex = argsLength === 1 ? arrayLength : Math.min(startIndex + (args[1] || 0), arrayLength),
                    endAddIndex = startIndex + argsLength - 2,
                    endIndex = Math.max(endDeleteIndex, endAddIndex),
                    additions = [], deletions = [];
                for (var index = startIndex, argsIndex = 2; index < endIndex; ++index, ++argsIndex) {
                    if (index < endDeleteIndex)
                        deletions.push(pushDiff('deleted', rawArray[index], index));
                    if (index < endAddIndex)
                        additions.push(pushDiff('added', args[argsIndex], index));
                }
                ko.utils.findMovesInArrayComparison(deletions, additions);
                break;

            default:
                return;
        }
        cachedDiff = diff;
    };
};
var computedState = ko.utils.createSymbolOrString('_state');

ko.computed = ko.dependentObservable = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget, options) {
    if (typeof evaluatorFunctionOrOptions === "object") {
        // Single-parameter syntax - everything is on this "options" param
        options = evaluatorFunctionOrOptions;
    } else {
        // Multi-parameter syntax - construct the options according to the params passed
        options = options || {};
        if (evaluatorFunctionOrOptions) {
            options["read"] = evaluatorFunctionOrOptions;
        }
    }
    if (typeof options["read"] != "function")
        throw Error("Pass a function that returns the value of the ko.computed");

    var writeFunction = options["write"];
    var state = {
        latestValue: undefined,
        isStale: true,
        isBeingEvaluated: false,
        suppressDisposalUntilDisposeWhenReturnsFalse: false,
        isDisposed: false,
        pure: false,
        isSleeping: false,
        readFunction: options["read"],
        evaluatorFunctionTarget: evaluatorFunctionTarget || options["owner"],
        disposeWhenNodeIsRemoved: options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,
        disposeWhen: options["disposeWhen"] || options.disposeWhen,
        domNodeDisposalCallback: null,
        dependencyTracking: {},
        dependenciesCount: 0,
        evaluationTimeoutInstance: null
    };

    function computedObservable() {
        if (arguments.length > 0) {
            if (typeof writeFunction === "function") {
                // Writing a value
                writeFunction.apply(state.evaluatorFunctionTarget, arguments);
            } else {
                throw new Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
            }
            return this; // Permits chained assignments
        } else {
            // Reading the value
            ko.dependencyDetection.registerDependency(computedObservable);
            if (state.isStale || (state.isSleeping && computedObservable.haveDependenciesChanged())) {
                computedObservable.evaluateImmediate();
            }
            return state.latestValue;
        }
    }

    computedObservable[computedState] = state;
    computedObservable.hasWriteFunction = typeof writeFunction === "function";

    // Inherit from 'subscribable'
    if (!ko.utils.canSetPrototype) {
        // 'subscribable' won't be on the prototype chain unless we put it there directly
        ko.utils.extend(computedObservable, ko.subscribable['fn']);
    }
    ko.subscribable['fn'].init(computedObservable);

    // Inherit from 'computed'
    ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);

    if (options['pure']) {
        state.pure = true;
        state.isSleeping = true;     // Starts off sleeping; will awake on the first subscription
        ko.utils.extend(computedObservable, pureComputedOverrides);
    } else if (options['deferEvaluation']) {
        ko.utils.extend(computedObservable, deferEvaluationOverrides);
    }

    if (ko.options['deferUpdates']) {
        ko.extenders['deferred'](computedObservable, true);
    }

    if (DEBUG) {
        // #1731 - Aid debugging by exposing the computed's options
        computedObservable["_options"] = options;
    }

    if (state.disposeWhenNodeIsRemoved) {
        // Since this computed is associated with a DOM node, and we don't want to dispose the computed
        // until the DOM node is *removed* from the document (as opposed to never having been in the document),
        // we'll prevent disposal until "disposeWhen" first returns false.
        state.suppressDisposalUntilDisposeWhenReturnsFalse = true;

        // disposeWhenNodeIsRemoved: true can be used to opt into the "only dispose after first false result"
        // behaviour even if there's no specific node to watch. In that case, clear the option so we don't try
        // to watch for a non-node's disposal. This technique is intended for KO's internal use only and shouldn't
        // be documented or used by application code, as it's likely to change in a future version of KO.
        if (!state.disposeWhenNodeIsRemoved.nodeType) {
            state.disposeWhenNodeIsRemoved = null;
        }
    }

    // Evaluate, unless sleeping or deferEvaluation is true
    if (!state.isSleeping && !options['deferEvaluation']) {
        computedObservable.evaluateImmediate();
    }

    // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
    // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
    if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {
        ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {
            computedObservable.dispose();
        });
    }

    return computedObservable;
};

// Utility function that disposes a given dependencyTracking entry
function computedDisposeDependencyCallback(id, entryToDispose) {
    if (entryToDispose !== null && entryToDispose.dispose) {
        entryToDispose.dispose();
    }
}

// This function gets called each time a dependency is detected while evaluating a computed.
// It's factored out as a shared function to avoid creating unnecessary function instances during evaluation.
function computedBeginDependencyDetectionCallback(subscribable, id) {
    var computedObservable = this.computedObservable,
        state = computedObservable[computedState];
    if (!state.isDisposed) {
        if (this.disposalCount && this.disposalCandidates[id]) {
            // Don't want to dispose this subscription, as it's still being used
            computedObservable.addDependencyTracking(id, subscribable, this.disposalCandidates[id]);
            this.disposalCandidates[id] = null; // No need to actually delete the property - disposalCandidates is a transient object anyway
            --this.disposalCount;
        } else if (!state.dependencyTracking[id]) {
            // Brand new subscription - add it
            computedObservable.addDependencyTracking(id, subscribable, state.isSleeping ? { _target: subscribable } : computedObservable.subscribeToDependency(subscribable));
        }
    }
}

var computedFn = {
    "equalityComparer": valuesArePrimitiveAndEqual,
    getDependenciesCount: function () {
        return this[computedState].dependenciesCount;
    },
    addDependencyTracking: function (id, target, trackingObj) {
        if (this[computedState].pure && target === this) {
            throw Error("A 'pure' computed must not be called recursively");
        }

        this[computedState].dependencyTracking[id] = trackingObj;
        trackingObj._order = this[computedState].dependenciesCount++;
        trackingObj._version = target.getVersion();
    },
    haveDependenciesChanged: function () {
        var id, dependency, dependencyTracking = this[computedState].dependencyTracking;
        for (id in dependencyTracking) {
            if (dependencyTracking.hasOwnProperty(id)) {
                dependency = dependencyTracking[id];
                if (dependency._target.hasChanged(dependency._version)) {
                    return true;
                }
            }
        }
    },
    markDirty: function () {
        // Process "dirty" events if we can handle delayed notifications
        if (this._evalDelayed && !this[computedState].isBeingEvaluated) {
            this._evalDelayed();
        }
    },
    isActive: function () {
        return this[computedState].isStale || this[computedState].dependenciesCount > 0;
    },
    respondToChange: function () {
        // Ignore "change" events if we've already scheduled a delayed notification
        if (!this._notificationIsPending) {
            this.evaluatePossiblyAsync();
        }
    },
    subscribeToDependency: function (target) {
        if (target._deferUpdates && !this[computedState].disposeWhenNodeIsRemoved) {
            var dirtySub = target.subscribe(this.markDirty, this, 'dirty'),
                changeSub = target.subscribe(this.respondToChange, this);
            return {
                _target: target,
                dispose: function () {
                    dirtySub.dispose();
                    changeSub.dispose();
                }
            };
        } else {
            return target.subscribe(this.evaluatePossiblyAsync, this);
        }
    },
    evaluatePossiblyAsync: function () {
        var computedObservable = this,
            throttleEvaluationTimeout = computedObservable['throttleEvaluation'];
        if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
            clearTimeout(this[computedState].evaluationTimeoutInstance);
            this[computedState].evaluationTimeoutInstance = ko.utils.setTimeout(function () {
                computedObservable.evaluateImmediate(true /*notifyChange*/);
            }, throttleEvaluationTimeout);
        } else if (computedObservable._evalDelayed) {
            computedObservable._evalDelayed();
        } else {
            computedObservable.evaluateImmediate(true /*notifyChange*/);
        }
    },
    evaluateImmediate: function (notifyChange) {
        var computedObservable = this,
            state = computedObservable[computedState],
            disposeWhen = state.disposeWhen;

        if (state.isBeingEvaluated) {
            // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
            // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
            // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
            // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
            return;
        }

        // Do not evaluate (and possibly capture new dependencies) if disposed
        if (state.isDisposed) {
            return;
        }

        if (state.disposeWhenNodeIsRemoved && !ko.utils.domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {
            // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse
            if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {
                computedObservable.dispose();
                return;
            }
        } else {
            // It just did return false, so we can stop suppressing now
            state.suppressDisposalUntilDisposeWhenReturnsFalse = false;
        }

        state.isBeingEvaluated = true;
        try {
            this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);
        } finally {
            state.isBeingEvaluated = false;
        }

        if (!state.dependenciesCount) {
            computedObservable.dispose();
        }
    },
    evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {
        // This function is really just part of the evaluateImmediate logic. You would never call it from anywhere else.
        // Factoring it out into a separate function means it can be independent of the try/catch block in evaluateImmediate,
        // which contributes to saving about 40% off the CPU overhead of computed evaluation (on V8 at least).

        var computedObservable = this,
            state = computedObservable[computedState];

        // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
        // Then, during evaluation, we cross off any that are in fact still being used.
        var isInitial = state.pure ? undefined : !state.dependenciesCount,   // If we're evaluating when there are no previous dependencies, it must be the first time
            dependencyDetectionContext = {
                computedObservable: computedObservable,
                disposalCandidates: state.dependencyTracking,
                disposalCount: state.dependenciesCount
            };

        ko.dependencyDetection.begin({
            callbackTarget: dependencyDetectionContext,
            callback: computedBeginDependencyDetectionCallback,
            computed: computedObservable,
            isInitial: isInitial
        });

        state.dependencyTracking = {};
        state.dependenciesCount = 0;

        var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);

        if (computedObservable.isDifferent(state.latestValue, newValue)) {
            if (!state.isSleeping) {
                computedObservable["notifySubscribers"](state.latestValue, "beforeChange");
            }

            state.latestValue = newValue;

            if (state.isSleeping) {
                computedObservable.updateVersion();
            } else if (notifyChange) {
                computedObservable["notifySubscribers"](state.latestValue);
            }
        }

        if (isInitial) {
            computedObservable["notifySubscribers"](state.latestValue, "awake");
        }
    },
    evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {
        // This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.
        // You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection
        // can be independent of try/finally blocks, which contributes to saving about 40% off the CPU
        // overhead of computed evaluation (on V8 at least).

        try {
            var readFunction = state.readFunction;
            return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();
        } finally {
            ko.dependencyDetection.end();

            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
            if (dependencyDetectionContext.disposalCount && !state.isSleeping) {
                ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);
            }

            state.isStale = false;
        }
    },
    peek: function () {
        // Peek won't re-evaluate, except while the computed is sleeping or to get the initial value when "deferEvaluation" is set.
        var state = this[computedState];
        if ((state.isStale && !state.dependenciesCount) || (state.isSleeping && this.haveDependenciesChanged())) {
            this.evaluateImmediate();
        }
        return state.latestValue;
    },
    limit: function (limitFunction) {
        // Override the limit function with one that delays evaluation as well
        ko.subscribable['fn'].limit.call(this, limitFunction);
        this._evalDelayed = function () {
            this._limitBeforeChange(this[computedState].latestValue);

            this[computedState].isStale = true; // Mark as dirty

            // Pass the observable to the "limit" code, which will access it when
            // it's time to do the notification.
            this._limitChange(this);
        }
    },
    dispose: function () {
        var state = this[computedState];
        if (!state.isSleeping && state.dependencyTracking) {
            ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
                if (dependency.dispose)
                    dependency.dispose();
            });
        }
        if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {
            ko.utils.domNodeDisposal.removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);
        }
        state.dependencyTracking = null;
        state.dependenciesCount = 0;
        state.isDisposed = true;
        state.isStale = false;
        state.isSleeping = false;
        state.disposeWhenNodeIsRemoved = null;
    }
};

var pureComputedOverrides = {
    beforeSubscriptionAdd: function (event) {
        // If asleep, wake up the computed by subscribing to any dependencies.
        var computedObservable = this,
            state = computedObservable[computedState];
        if (!state.isDisposed && state.isSleeping && event == 'change') {
            state.isSleeping = false;
            if (state.isStale || computedObservable.haveDependenciesChanged()) {
                state.dependencyTracking = null;
                state.dependenciesCount = 0;
                state.isStale = true;
                computedObservable.evaluateImmediate();
            } else {
                // First put the dependencies in order
                var dependeciesOrder = [];
                ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
                    dependeciesOrder[dependency._order] = id;
                });
                // Next, subscribe to each one
                ko.utils.arrayForEach(dependeciesOrder, function (id, order) {
                    var dependency = state.dependencyTracking[id],
                        subscription = computedObservable.subscribeToDependency(dependency._target);
                    subscription._order = order;
                    subscription._version = dependency._version;
                    state.dependencyTracking[id] = subscription;
                });
            }
            if (!state.isDisposed) {     // test since evaluating could trigger disposal
                computedObservable["notifySubscribers"](state.latestValue, "awake");
            }
        }
    },
    afterSubscriptionRemove: function (event) {
        var state = this[computedState];
        if (!state.isDisposed && event == 'change' && !this.hasSubscriptionsForEvent('change')) {
            ko.utils.objectForEach(state.dependencyTracking, function (id, dependency) {
                if (dependency.dispose) {
                    state.dependencyTracking[id] = {
                        _target: dependency._target,
                        _order: dependency._order,
                        _version: dependency._version
                    };
                    dependency.dispose();
                }
            });
            state.isSleeping = true;
            this["notifySubscribers"](undefined, "asleep");
        }
    },
    getVersion: function () {
        // Because a pure computed is not automatically updated while it is sleeping, we can't
        // simply return the version number. Instead, we check if any of the dependencies have
        // changed and conditionally re-evaluate the computed observable.
        var state = this[computedState];
        if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {
            this.evaluateImmediate();
        }
        return ko.subscribable['fn'].getVersion.call(this);
    }
};

var deferEvaluationOverrides = {
    beforeSubscriptionAdd: function (event) {
        // This will force a computed with deferEvaluation to evaluate when the first subscription is registered.
        if (event == 'change' || event == 'beforeChange') {
            this.peek();
        }
    }
};

// Note that for browsers that don't support proto assignment, the
// inheritance chain is created manually in the ko.computed constructor
if (ko.utils.canSetPrototype) {
    ko.utils.setPrototypeOf(computedFn, ko.subscribable['fn']);
}

// Set the proto chain values for ko.hasPrototype
var protoProp = ko.observable.protoProperty; // == "__ko_proto__"
ko.computed[protoProp] = ko.observable;
computedFn[protoProp] = ko.computed;

ko.isComputed = function (instance) {
    return ko.hasPrototype(instance, ko.computed);
};

ko.isPureComputed = function (instance) {
    return ko.hasPrototype(instance, ko.computed)
        && instance[computedState] && instance[computedState].pure;
};

ko.exportSymbol('computed', ko.computed);
ko.exportSymbol('dependentObservable', ko.computed);    // export ko.dependentObservable for backwards compatibility (1.x)
ko.exportSymbol('isComputed', ko.isComputed);
ko.exportSymbol('isPureComputed', ko.isPureComputed);
ko.exportSymbol('computed.fn', computedFn);
ko.exportProperty(computedFn, 'peek', computedFn.peek);
ko.exportProperty(computedFn, 'dispose', computedFn.dispose);
ko.exportProperty(computedFn, 'isActive', computedFn.isActive);
ko.exportProperty(computedFn, 'getDependenciesCount', computedFn.getDependenciesCount);

ko.pureComputed = function (evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
    if (typeof evaluatorFunctionOrOptions === 'function') {
        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, {'pure':true});
    } else {
        evaluatorFunctionOrOptions = ko.utils.extend({}, evaluatorFunctionOrOptions);   // make a copy of the parameter object
        evaluatorFunctionOrOptions['pure'] = true;
        return ko.computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
    }
}
ko.exportSymbol('pureComputed', ko.pureComputed);

(function() {
    var maxNestedObservableDepth = 10; // Escape the (unlikely) pathalogical case where an observable's current value is itself (or similar reference cycle)

    ko.toJS = function(rootObject) {
        if (arguments.length == 0)
            throw new Error("When calling ko.toJS, pass the object you want to convert.");

        // We just unwrap everything at every level in the object graph
        return mapJsObjectGraph(rootObject, function(valueToMap) {
            // Loop because an observable's value might in turn be another observable wrapper
            for (var i = 0; ko.isObservable(valueToMap) && (i < maxNestedObservableDepth); i++)
                valueToMap = valueToMap();
            return valueToMap;
        });
    };

    ko.toJSON = function(rootObject, replacer, space) {     // replacer and space are optional
        var plainJavaScriptObject = ko.toJS(rootObject);
        return ko.utils.stringifyJson(plainJavaScriptObject, replacer, space);
    };

    function mapJsObjectGraph(rootObject, mapInputCallback, visitedObjects) {
        visitedObjects = visitedObjects || new objectLookup();

        rootObject = mapInputCallback(rootObject);
        var canHaveProperties = (typeof rootObject == "object") && (rootObject !== null) && (rootObject !== undefined) && (!(rootObject instanceof RegExp)) && (!(rootObject instanceof Date)) && (!(rootObject instanceof String)) && (!(rootObject instanceof Number)) && (!(rootObject instanceof Boolean));
        if (!canHaveProperties)
            return rootObject;

        var outputProperties = rootObject instanceof Array ? [] : {};
        visitedObjects.save(rootObject, outputProperties);

        visitPropertiesOrArrayEntries(rootObject, function(indexer) {
            var propertyValue = mapInputCallback(rootObject[indexer]);

            switch (typeof propertyValue) {
                case "boolean":
                case "number":
                case "string":
                case "function":
                    outputProperties[indexer] = propertyValue;
                    break;
                case "object":
                case "undefined":
                    var previouslyMappedValue = visitedObjects.get(propertyValue);
                    outputProperties[indexer] = (previouslyMappedValue !== undefined)
                        ? previouslyMappedValue
                        : mapJsObjectGraph(propertyValue, mapInputCallback, visitedObjects);
                    break;
            }
        });

        return outputProperties;
    }

    function visitPropertiesOrArrayEntries(rootObject, visitorCallback) {
        if (rootObject instanceof Array) {
            for (var i = 0; i < rootObject.length; i++)
                visitorCallback(i);

            // For arrays, also respect toJSON property for custom mappings (fixes #278)
            if (typeof rootObject['toJSON'] == 'function')
                visitorCallback('toJSON');
        } else {
            for (var propertyName in rootObject) {
                visitorCallback(propertyName);
            }
        }
    };

    function objectLookup() {
        this.keys = [];
        this.values = [];
    };

    objectLookup.prototype = {
        constructor: objectLookup,
        save: function(key, value) {
            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
            if (existingIndex >= 0)
                this.values[existingIndex] = value;
            else {
                this.keys.push(key);
                this.values.push(value);
            }
        },
        get: function(key) {
            var existingIndex = ko.utils.arrayIndexOf(this.keys, key);
            return (existingIndex >= 0) ? this.values[existingIndex] : undefined;
        }
    };
})();

ko.exportSymbol('toJS', ko.toJS);
ko.exportSymbol('toJSON', ko.toJSON);
(function () {
    var hasDomDataExpandoProperty = '__ko__hasDomDataOptionValue__';

    // Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
    // are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
    // that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
    ko.selectExtensions = {
        readValue : function(element) {
            switch (ko.utils.tagNameLower(element)) {
                case 'option':
                    if (element[hasDomDataExpandoProperty] === true)
                        return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
                    return ko.utils.ieVersion <= 7
                        ? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
                        : element.value;
                case 'select':
                    return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
                default:
                    return element.value;
            }
        },

        writeValue: function(element, value, allowUnset) {
            switch (ko.utils.tagNameLower(element)) {
                case 'option':
                    switch(typeof value) {
                        case "string":
                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
                            if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
                                delete element[hasDomDataExpandoProperty];
                            }
                            element.value = value;
                            break;
                        default:
                            // Store arbitrary object using DomData
                            ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
                            element[hasDomDataExpandoProperty] = true;

                            // Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
                            element.value = typeof value === "number" ? value : "";
                            break;
                    }
                    break;
                case 'select':
                    if (value === "" || value === null)       // A blank string or null value will select the caption
                        value = undefined;
                    var selection = -1;
                    for (var i = 0, n = element.options.length, optionValue; i < n; ++i) {
                        optionValue = ko.selectExtensions.readValue(element.options[i]);
                        // Include special check to handle selecting a caption with a blank string value
                        if (optionValue == value || (optionValue == "" && value === undefined)) {
                            selection = i;
                            break;
                        }
                    }
                    if (allowUnset || selection >= 0 || (value === undefined && element.size > 1)) {
                        element.selectedIndex = selection;
                    }
                    break;
                default:
                    if ((value === null) || (value === undefined))
                        value = "";
                    element.value = value;
                    break;
            }
        }
    };
})();

ko.exportSymbol('selectExtensions', ko.selectExtensions);
ko.exportSymbol('selectExtensions.readValue', ko.selectExtensions.readValue);
ko.exportSymbol('selectExtensions.writeValue', ko.selectExtensions.writeValue);
ko.expressionRewriting = (function () {
    var javaScriptReservedWords = ["true", "false", "null", "undefined"];

    // Matches something that can be assigned to--either an isolated identifier or something ending with a property accessor
    // This is designed to be simple and avoid false negatives, but could produce false positives (e.g., a+b.c).
    // This also will not properly handle nested brackets (e.g., obj1[obj2['prop']]; see #911).
    var javaScriptAssignmentTarget = /^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i;

    function getWriteableValue(expression) {
        if (ko.utils.arrayIndexOf(javaScriptReservedWords, expression) >= 0)
            return false;
        var match = expression.match(javaScriptAssignmentTarget);
        return match === null ? false : match[1] ? ('Object(' + match[1] + ')' + match[2]) : expression;
    }

    // The following regular expressions will be used to split an object-literal string into tokens

        // These two match strings, either with double quotes or single quotes
    var stringDouble = '"(?:[^"\\\\]|\\\\.)*"',
        stringSingle = "'(?:[^'\\\\]|\\\\.)*'",
        // Matches a regular expression (text enclosed by slashes), but will also match sets of divisions
        // as a regular expression (this is handled by the parsing loop below).
        stringRegexp = '/(?:[^/\\\\]|\\\\.)*/\w*',
        // These characters have special meaning to the parser and must not appear in the middle of a
        // token, except as part of a string.
        specials = ',"\'{}()/:[\\]',
        // Match text (at least two characters) that does not contain any of the above special characters,
        // although some of the special characters are allowed to start it (all but the colon and comma).
        // The text can contain spaces, but leading or trailing spaces are skipped.
        everyThingElse = '[^\\s:,/][^' + specials + ']*[^\\s' + specials + ']',
        // Match any non-space character not matched already. This will match colons and commas, since they're
        // not matched by "everyThingElse", but will also match any other single character that wasn't already
        // matched (for example: in "a: 1, b: 2", each of the non-space characters will be matched by oneNotSpace).
        oneNotSpace = '[^\\s]',

        // Create the actual regular expression by or-ing the above strings. The order is important.
        bindingToken = RegExp(stringDouble + '|' + stringSingle + '|' + stringRegexp + '|' + everyThingElse + '|' + oneNotSpace, 'g'),

        // Match end of previous token to determine whether a slash is a division or regex.
        divisionLookBehind = /[\])"'A-Za-z0-9_$]+$/,
        keywordRegexLookBehind = {'in':1,'return':1,'typeof':1};

    function parseObjectLiteral(objectLiteralString) {
        // Trim leading and trailing spaces from the string
        var str = ko.utils.stringTrim(objectLiteralString);

        // Trim braces '{' surrounding the whole object literal
        if (str.charCodeAt(0) === 123) str = str.slice(1, -1);

        // Split into tokens
        var result = [], toks = str.match(bindingToken), key, values = [], depth = 0;

        if (toks) {
            // Append a comma so that we don't need a separate code block to deal with the last item
            toks.push(',');

            for (var i = 0, tok; tok = toks[i]; ++i) {
                var c = tok.charCodeAt(0);
                // A comma signals the end of a key/value pair if depth is zero
                if (c === 44) { // ","
                    if (depth <= 0) {
                        result.push((key && values.length) ? {key: key, value: values.join('')} : {'unknown': key || values.join('')});
                        key = depth = 0;
                        values = [];
                        continue;
                    }
                // Simply skip the colon that separates the name and value
                } else if (c === 58) { // ":"
                    if (!depth && !key && values.length === 1) {
                        key = values.pop();
                        continue;
                    }
                // A set of slashes is initially matched as a regular expression, but could be division
                } else if (c === 47 && i && tok.length > 1) {  // "/"
                    // Look at the end of the previous token to determine if the slash is actually division
                    var match = toks[i-1].match(divisionLookBehind);
                    if (match && !keywordRegexLookBehind[match[0]]) {
                        // The slash is actually a division punctuator; re-parse the remainder of the string (not including the slash)
                        str = str.substr(str.indexOf(tok) + 1);
                        toks = str.match(bindingToken);
                        toks.push(',');
                        i = -1;
                        // Continue with just the slash
                        tok = '/';
                    }
                // Increment depth for parentheses, braces, and brackets so that interior commas are ignored
                } else if (c === 40 || c === 123 || c === 91) { // '(', '{', '['
                    ++depth;
                } else if (c === 41 || c === 125 || c === 93) { // ')', '}', ']'
                    --depth;
                // The key will be the first token; if it's a string, trim the quotes
                } else if (!key && !values.length && (c === 34 || c === 39)) { // '"', "'"
                    tok = tok.slice(1, -1);
                }
                values.push(tok);
            }
        }
        return result;
    }

    // Two-way bindings include a write function that allow the handler to update the value even if it's not an observable.
    var twoWayBindings = {};

    function preProcessBindings(bindingsStringOrKeyValueArray, bindingOptions) {
        bindingOptions = bindingOptions || {};

        function processKeyValue(key, val) {
            var writableVal;
            function callPreprocessHook(obj) {
                return (obj && obj['preprocess']) ? (val = obj['preprocess'](val, key, processKeyValue)) : true;
            }
            if (!bindingParams) {
                if (!callPreprocessHook(ko['getBindingHandler'](key)))
                    return;

                if (twoWayBindings[key] && (writableVal = getWriteableValue(val))) {
                    // For two-way bindings, provide a write method in case the value
                    // isn't a writable observable.
                    propertyAccessorResultStrings.push("'" + key + "':function(_z){" + writableVal + "=_z}");
                }
            }
            // Values are wrapped in a function so that each value can be accessed independently
            if (makeValueAccessors) {
                val = 'function(){return ' + val + ' }';
            }
            resultStrings.push("'" + key + "':" + val);
        }

        var resultStrings = [],
            propertyAccessorResultStrings = [],
            makeValueAccessors = bindingOptions['valueAccessors'],
            bindingParams = bindingOptions['bindingParams'],
            keyValueArray = typeof bindingsStringOrKeyValueArray === "string" ?
                parseObjectLiteral(bindingsStringOrKeyValueArray) : bindingsStringOrKeyValueArray;

        ko.utils.arrayForEach(keyValueArray, function(keyValue) {
            processKeyValue(keyValue.key || keyValue['unknown'], keyValue.value);
        });

        if (propertyAccessorResultStrings.length)
            processKeyValue('_ko_property_writers', "{" + propertyAccessorResultStrings.join(",") + " }");

        return resultStrings.join(",");
    }

    return {
        bindingRewriteValidators: [],

        twoWayBindings: twoWayBindings,

        parseObjectLiteral: parseObjectLiteral,

        preProcessBindings: preProcessBindings,

        keyValueArrayContainsKey: function(keyValueArray, key) {
            for (var i = 0; i < keyValueArray.length; i++)
                if (keyValueArray[i]['key'] == key)
                    return true;
            return false;
        },

        // Internal, private KO utility for updating model properties from within bindings
        // property:            If the property being updated is (or might be) an observable, pass it here
        //                      If it turns out to be a writable observable, it will be written to directly
        // allBindings:         An object with a get method to retrieve bindings in the current execution context.
        //                      This will be searched for a '_ko_property_writers' property in case you're writing to a non-observable
        // key:                 The key identifying the property to be written. Example: for { hasFocus: myValue }, write to 'myValue' by specifying the key 'hasFocus'
        // value:               The value to be written
        // checkIfDifferent:    If true, and if the property being written is a writable observable, the value will only be written if
        //                      it is !== existing value on that writable observable
        writeValueToProperty: function(property, allBindings, key, value, checkIfDifferent) {
            if (!property || !ko.isObservable(property)) {
                var propWriters = allBindings.get('_ko_property_writers');
                if (propWriters && propWriters[key])
                    propWriters[key](value);
            } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
                property(value);
            }
        }
    };
})();

ko.exportSymbol('expressionRewriting', ko.expressionRewriting);
ko.exportSymbol('expressionRewriting.bindingRewriteValidators', ko.expressionRewriting.bindingRewriteValidators);
ko.exportSymbol('expressionRewriting.parseObjectLiteral', ko.expressionRewriting.parseObjectLiteral);
ko.exportSymbol('expressionRewriting.preProcessBindings', ko.expressionRewriting.preProcessBindings);

// Making bindings explicitly declare themselves as "two way" isn't ideal in the long term (it would be better if
// all bindings could use an official 'property writer' API without needing to declare that they might). However,
// since this is not, and has never been, a public API (_ko_property_writers was never documented), it's acceptable
// as an internal implementation detail in the short term.
// For those developers who rely on _ko_property_writers in their custom bindings, we expose _twoWayBindings as an
// undocumented feature that makes it relatively easy to upgrade to KO 3.0. However, this is still not an official
// public API, and we reserve the right to remove it at any time if we create a real public property writers API.
ko.exportSymbol('expressionRewriting._twoWayBindings', ko.expressionRewriting.twoWayBindings);

// For backward compatibility, define the following aliases. (Previously, these function names were misleading because
// they referred to JSON specifically, even though they actually work with arbitrary JavaScript object literal expressions.)
ko.exportSymbol('jsonExpressionRewriting', ko.expressionRewriting);
ko.exportSymbol('jsonExpressionRewriting.insertPropertyAccessorsIntoJson', ko.expressionRewriting.preProcessBindings);
(function() {
    // "Virtual elements" is an abstraction on top of the usual DOM API which understands the notion that comment nodes
    // may be used to represent hierarchy (in addition to the DOM's natural hierarchy).
    // If you call the DOM-manipulating functions on ko.virtualElements, you will be able to read and write the state
    // of that virtual hierarchy
    //
    // The point of all this is to support containerless templates (e.g., <!-- ko foreach:someCollection -->blah<!-- /ko -->)
    // without having to scatter special cases all over the binding and templating code.

    // IE 9 cannot reliably read the "nodeValue" property of a comment node (see https://github.com/SteveSanderson/knockout/issues/186)
    // but it does give them a nonstandard alternative property called "text" that it can read reliably. Other browsers don't have that property.
    // So, use node.text where available, and node.nodeValue elsewhere
    var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->";

    var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/;
    var endCommentRegex =   commentNodesHaveTextProperty ? /^<!--\s*\/ko\s*-->$/ : /^\s*\/ko\s*$/;
    var htmlTagsWithOptionallyClosingChildren = { 'ul': true, 'ol': true };

    function isStartComment(node) {
        return (node.nodeType == 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
    }

    function isEndComment(node) {
        return (node.nodeType == 8) && endCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue);
    }

    function getVirtualChildren(startComment, allowUnbalanced) {
        var currentNode = startComment;
        var depth = 1;
        var children = [];
        while (currentNode = currentNode.nextSibling) {
            if (isEndComment(currentNode)) {
                depth--;
                if (depth === 0)
                    return children;
            }

            children.push(currentNode);

            if (isStartComment(currentNode))
                depth++;
        }
        if (!allowUnbalanced)
            throw new Error("Cannot find closing comment tag to match: " + startComment.nodeValue);
        return null;
    }

    function getMatchingEndComment(startComment, allowUnbalanced) {
        var allVirtualChildren = getVirtualChildren(startComment, allowUnbalanced);
        if (allVirtualChildren) {
            if (allVirtualChildren.length > 0)
                return allVirtualChildren[allVirtualChildren.length - 1].nextSibling;
            return startComment.nextSibling;
        } else
            return null; // Must have no matching end comment, and allowUnbalanced is true
    }

    function getUnbalancedChildTags(node) {
        // e.g., from <div>OK</div><!-- ko blah --><span>Another</span>, returns: <!-- ko blah --><span>Another</span>
        //       from <div>OK</div><!-- /ko --><!-- /ko -->,             returns: <!-- /ko --><!-- /ko -->
        var childNode = node.firstChild, captureRemaining = null;
        if (childNode) {
            do {
                if (captureRemaining)                   // We already hit an unbalanced node and are now just scooping up all subsequent nodes
                    captureRemaining.push(childNode);
                else if (isStartComment(childNode)) {
                    var matchingEndComment = getMatchingEndComment(childNode, /* allowUnbalanced: */ true);
                    if (matchingEndComment)             // It's a balanced tag, so skip immediately to the end of this virtual set
                        childNode = matchingEndComment;
                    else
                        captureRemaining = [childNode]; // It's unbalanced, so start capturing from this point
                } else if (isEndComment(childNode)) {
                    captureRemaining = [childNode];     // It's unbalanced (if it wasn't, we'd have skipped over it already), so start capturing
                }
            } while (childNode = childNode.nextSibling);
        }
        return captureRemaining;
    }

    ko.virtualElements = {
        allowedBindings: {},

        childNodes: function(node) {
            return isStartComment(node) ? getVirtualChildren(node) : node.childNodes;
        },

        emptyNode: function(node) {
            if (!isStartComment(node))
                ko.utils.emptyDomNode(node);
            else {
                var virtualChildren = ko.virtualElements.childNodes(node);
                for (var i = 0, j = virtualChildren.length; i < j; i++)
                    ko.removeNode(virtualChildren[i]);
            }
        },

        setDomNodeChildren: function(node, childNodes) {
            if (!isStartComment(node))
                ko.utils.setDomNodeChildren(node, childNodes);
            else {
                ko.virtualElements.emptyNode(node);
                var endCommentNode = node.nextSibling; // Must be the next sibling, as we just emptied the children
                for (var i = 0, j = childNodes.length; i < j; i++)
                    endCommentNode.parentNode.insertBefore(childNodes[i], endCommentNode);
            }
        },

        prepend: function(containerNode, nodeToPrepend) {
            if (!isStartComment(containerNode)) {
                if (containerNode.firstChild)
                    containerNode.insertBefore(nodeToPrepend, containerNode.firstChild);
                else
                    containerNode.appendChild(nodeToPrepend);
            } else {
                // Start comments must always have a parent and at least one following sibling (the end comment)
                containerNode.parentNode.insertBefore(nodeToPrepend, containerNode.nextSibling);
            }
        },

        insertAfter: function(containerNode, nodeToInsert, insertAfterNode) {
            if (!insertAfterNode) {
                ko.virtualElements.prepend(containerNode, nodeToInsert);
            } else if (!isStartComment(containerNode)) {
                // Insert after insertion point
                if (insertAfterNode.nextSibling)
                    containerNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
                else
                    containerNode.appendChild(nodeToInsert);
            } else {
                // Children of start comments must always have a parent and at least one following sibling (the end comment)
                containerNode.parentNode.insertBefore(nodeToInsert, insertAfterNode.nextSibling);
            }
        },

        firstChild: function(node) {
            if (!isStartComment(node))
                return node.firstChild;
            if (!node.nextSibling || isEndComment(node.nextSibling))
                return null;
            return node.nextSibling;
        },

        nextSibling: function(node) {
            if (isStartComment(node))
                node = getMatchingEndComment(node);
            if (node.nextSibling && isEndComment(node.nextSibling))
                return null;
            return node.nextSibling;
        },

        hasBindingValue: isStartComment,

        virtualNodeBindingValue: function(node) {
            var regexMatch = (commentNodesHaveTextProperty ? node.text : node.nodeValue).match(startCommentRegex);
            return regexMatch ? regexMatch[1] : null;
        },

        normaliseVirtualElementDomStructure: function(elementVerified) {
            // Workaround for https://github.com/SteveSanderson/knockout/issues/155
            // (IE <= 8 or IE 9 quirks mode parses your HTML weirdly, treating closing </li> tags as if they don't exist, thereby moving comment nodes
            // that are direct descendants of <ul> into the preceding <li>)
            if (!htmlTagsWithOptionallyClosingChildren[ko.utils.tagNameLower(elementVerified)])
                return;

            // Scan immediate children to see if they contain unbalanced comment tags. If they do, those comment tags
            // must be intended to appear *after* that child, so move them there.
            var childNode = elementVerified.firstChild;
            if (childNode) {
                do {
                    if (childNode.nodeType === 1) {
                        var unbalancedTags = getUnbalancedChildTags(childNode);
                        if (unbalancedTags) {
                            // Fix up the DOM by moving the unbalanced tags to where they most likely were intended to be placed - *after* the child
                            var nodeToInsertBefore = childNode.nextSibling;
                            for (var i = 0; i < unbalancedTags.length; i++) {
                                if (nodeToInsertBefore)
                                    elementVerified.insertBefore(unbalancedTags[i], nodeToInsertBefore);
                                else
                                    elementVerified.appendChild(unbalancedTags[i]);
                            }
                        }
                    }
                } while (childNode = childNode.nextSibling);
            }
        }
    };
})();
ko.exportSymbol('virtualElements', ko.virtualElements);
ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);
ko.exportSymbol('virtualElements.emptyNode', ko.virtualElements.emptyNode);
//ko.exportSymbol('virtualElements.firstChild', ko.virtualElements.firstChild);     // firstChild is not minified
ko.exportSymbol('virtualElements.insertAfter', ko.virtualElements.insertAfter);
//ko.exportSymbol('virtualElements.nextSibling', ko.virtualElements.nextSibling);   // nextSibling is not minified
ko.exportSymbol('virtualElements.prepend', ko.virtualElements.prepend);
ko.exportSymbol('virtualElements.setDomNodeChildren', ko.virtualElements.setDomNodeChildren);
(function() {
    var defaultBindingAttributeName = "data-bind";

    ko.bindingProvider = function() {
        this.bindingCache = {};
    };

    ko.utils.extend(ko.bindingProvider.prototype, {
        'nodeHasBindings': function(node) {
            switch (node.nodeType) {
                case 1: // Element
                    return node.getAttribute(defaultBindingAttributeName) != null
                        || ko.components['getComponentNameForNode'](node);
                case 8: // Comment node
                    return ko.virtualElements.hasBindingValue(node);
                default: return false;
            }
        },

        'getBindings': function(node, bindingContext) {
            var bindingsString = this['getBindingsString'](node, bindingContext),
                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node) : null;
            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ false);
        },

        'getBindingAccessors': function(node, bindingContext) {
            var bindingsString = this['getBindingsString'](node, bindingContext),
                parsedBindings = bindingsString ? this['parseBindingsString'](bindingsString, bindingContext, node, { 'valueAccessors': true }) : null;
            return ko.components.addBindingsForCustomElement(parsedBindings, node, bindingContext, /* valueAccessors */ true);
        },

        // The following function is only used internally by this default provider.
        // It's not part of the interface definition for a general binding provider.
        'getBindingsString': function(node, bindingContext) {
            switch (node.nodeType) {
                case 1: return node.getAttribute(defaultBindingAttributeName);   // Element
                case 8: return ko.virtualElements.virtualNodeBindingValue(node); // Comment node
                default: return null;
            }
        },

        // The following function is only used internally by this default provider.
        // It's not part of the interface definition for a general binding provider.
        'parseBindingsString': function(bindingsString, bindingContext, node, options) {
            try {
                var bindingFunction = createBindingsStringEvaluatorViaCache(bindingsString, this.bindingCache, options);
                return bindingFunction(bindingContext, node);
            } catch (ex) {
                ex.message = "Unable to parse bindings.\nBindings value: " + bindingsString + "\nMessage: " + ex.message;
                throw ex;
            }
        }
    });

    ko.bindingProvider['instance'] = new ko.bindingProvider();

    function createBindingsStringEvaluatorViaCache(bindingsString, cache, options) {
        var cacheKey = bindingsString + (options && options['valueAccessors'] || '');
        return cache[cacheKey]
            || (cache[cacheKey] = createBindingsStringEvaluator(bindingsString, options));
    }

    function createBindingsStringEvaluator(bindingsString, options) {
        // Build the source for a function that evaluates "expression"
        // For each scope variable, add an extra level of "with" nesting
        // Example result: with(sc1) { with(sc0) { return (expression) } }
        var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
            functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}";
        return new Function("$context", "$element", functionBody);
    }
})();

ko.exportSymbol('bindingProvider', ko.bindingProvider);
(function () {
    ko.bindingHandlers = {};

    // The following element types will not be recursed into during binding.
    var bindingDoesNotRecurseIntoElementTypes = {
        // Don't want bindings that operate on text nodes to mutate <script> and <textarea> contents,
        // because it's unexpected and a potential XSS issue.
        // Also bindings should not operate on <template> elements since this breaks in Internet Explorer
        // and because such elements' contents are always intended to be bound in a different context
        // from where they appear in the document.
        'script': true,
        'textarea': true,
        'template': true
    };

    // Use an overridable method for retrieving binding handlers so that a plugins may support dynamically created handlers
    ko['getBindingHandler'] = function(bindingKey) {
        return ko.bindingHandlers[bindingKey];
    };

    // The ko.bindingContext constructor is only called directly to create the root context. For child
    // contexts, use bindingContext.createChildContext or bindingContext.extend.
    ko.bindingContext = function(dataItemOrAccessor, parentContext, dataItemAlias, extendCallback) {

        // The binding context object includes static properties for the current, parent, and root view models.
        // If a view model is actually stored in an observable, the corresponding binding context object, and
        // any child contexts, must be updated when the view model is changed.
        function updateContext() {
            // Most of the time, the context will directly get a view model object, but if a function is given,
            // we call the function to retrieve the view model. If the function accesses any observables or returns
            // an observable, the dependency is tracked, and those observables can later cause the binding
            // context to be updated.
            var dataItemOrObservable = isFunc ? dataItemOrAccessor() : dataItemOrAccessor,
                dataItem = ko.utils.unwrapObservable(dataItemOrObservable);

            if (parentContext) {
                // When a "parent" context is given, register a dependency on the parent context. Thus whenever the
                // parent context is updated, this context will also be updated.
                if (parentContext._subscribable)
                    parentContext._subscribable();

                // Copy $root and any custom properties from the parent context
                ko.utils.extend(self, parentContext);

                // Because the above copy overwrites our own properties, we need to reset them.
                // During the first execution, "subscribable" isn't set, so don't bother doing the update then.
                if (subscribable) {
                    self._subscribable = subscribable;
                }
            } else {
                self['$parents'] = [];
                self['$root'] = dataItem;

                // Export 'ko' in the binding context so it will be available in bindings and templates
                // even if 'ko' isn't exported as a global, such as when using an AMD loader.
                // See https://github.com/SteveSanderson/knockout/issues/490
                self['ko'] = ko;
            }
            self['$rawData'] = dataItemOrObservable;
            self['$data'] = dataItem;
            if (dataItemAlias)
                self[dataItemAlias] = dataItem;

            // The extendCallback function is provided when creating a child context or extending a context.
            // It handles the specific actions needed to finish setting up the binding context. Actions in this
            // function could also add dependencies to this binding context.
            if (extendCallback)
                extendCallback(self, parentContext, dataItem);

            return self['$data'];
        }
        function disposeWhen() {
            return nodes && !ko.utils.anyDomNodeIsAttachedToDocument(nodes);
        }

        var self = this,
            isFunc = typeof(dataItemOrAccessor) == "function" && !ko.isObservable(dataItemOrAccessor),
            nodes,
            subscribable = ko.dependentObservable(updateContext, null, { disposeWhen: disposeWhen, disposeWhenNodeIsRemoved: true });

        // At this point, the binding context has been initialized, and the "subscribable" computed observable is
        // subscribed to any observables that were accessed in the process. If there is nothing to track, the
        // computed will be inactive, and we can safely throw it away. If it's active, the computed is stored in
        // the context object.
        if (subscribable.isActive()) {
            self._subscribable = subscribable;

            // Always notify because even if the model ($data) hasn't changed, other context properties might have changed
            subscribable['equalityComparer'] = null;

            // We need to be able to dispose of this computed observable when it's no longer needed. This would be
            // easy if we had a single node to watch, but binding contexts can be used by many different nodes, and
            // we cannot assume that those nodes have any relation to each other. So instead we track any node that
            // the context is attached to, and dispose the computed when all of those nodes have been cleaned.

            // Add properties to *subscribable* instead of *self* because any properties added to *self* may be overwritten on updates
            nodes = [];
            subscribable._addNode = function(node) {
                nodes.push(node);
                ko.utils.domNodeDisposal.addDisposeCallback(node, function(node) {
                    ko.utils.arrayRemoveItem(nodes, node);
                    if (!nodes.length) {
                        subscribable.dispose();
                        self._subscribable = subscribable = undefined;
                    }
                });
            };
        }
    }

    // Extend the binding context hierarchy with a new view model object. If the parent context is watching
    // any observables, the new child context will automatically get a dependency on the parent context.
    // But this does not mean that the $data value of the child context will also get updated. If the child
    // view model also depends on the parent view model, you must provide a function that returns the correct
    // view model on each update.
    ko.bindingContext.prototype['createChildContext'] = function (dataItemOrAccessor, dataItemAlias, extendCallback) {
        return new ko.bindingContext(dataItemOrAccessor, this, dataItemAlias, function(self, parentContext) {
            // Extend the context hierarchy by setting the appropriate pointers
            self['$parentContext'] = parentContext;
            self['$parent'] = parentContext['$data'];
            self['$parents'] = (parentContext['$parents'] || []).slice(0);
            self['$parents'].unshift(self['$parent']);
            if (extendCallback)
                extendCallback(self);
        });
    };

    // Extend the binding context with new custom properties. This doesn't change the context hierarchy.
    // Similarly to "child" contexts, provide a function here to make sure that the correct values are set
    // when an observable view model is updated.
    ko.bindingContext.prototype['extend'] = function(properties) {
        // If the parent context references an observable view model, "_subscribable" will always be the
        // latest view model object. If not, "_subscribable" isn't set, and we can use the static "$data" value.
        return new ko.bindingContext(this._subscribable || this['$data'], this, null, function(self, parentContext) {
            // This "child" context doesn't directly track a parent observable view model,
            // so we need to manually set the $rawData value to match the parent.
            self['$rawData'] = parentContext['$rawData'];
            ko.utils.extend(self, typeof(properties) == "function" ? properties() : properties);
        });
    };

    // Returns the valueAccesor function for a binding value
    function makeValueAccessor(value) {
        return function() {
            return value;
        };
    }

    // Returns the value of a valueAccessor function
    function evaluateValueAccessor(valueAccessor) {
        return valueAccessor();
    }

    // Given a function that returns bindings, create and return a new object that contains
    // binding value-accessors functions. Each accessor function calls the original function
    // so that it always gets the latest value and all dependencies are captured. This is used
    // by ko.applyBindingsToNode and getBindingsAndMakeAccessors.
    function makeAccessorsFromFunction(callback) {
        return ko.utils.objectMap(ko.dependencyDetection.ignore(callback), function(value, key) {
            return function() {
                return callback()[key];
            };
        });
    }

    // Given a bindings function or object, create and return a new object that contains
    // binding value-accessors functions. This is used by ko.applyBindingsToNode.
    function makeBindingAccessors(bindings, context, node) {
        if (typeof bindings === 'function') {
            return makeAccessorsFromFunction(bindings.bind(null, context, node));
        } else {
            return ko.utils.objectMap(bindings, makeValueAccessor);
        }
    }

    // This function is used if the binding provider doesn't include a getBindingAccessors function.
    // It must be called with 'this' set to the provider instance.
    function getBindingsAndMakeAccessors(node, context) {
        return makeAccessorsFromFunction(this['getBindings'].bind(this, node, context));
    }

    function validateThatBindingIsAllowedForVirtualElements(bindingName) {
        var validator = ko.virtualElements.allowedBindings[bindingName];
        if (!validator)
            throw new Error("The binding '" + bindingName + "' cannot be used with virtual elements")
    }

    function applyBindingsToDescendantsInternal (bindingContext, elementOrVirtualElement, bindingContextsMayDifferFromDomParentElement) {
        var currentChild,
            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement),
            provider = ko.bindingProvider['instance'],
            preprocessNode = provider['preprocessNode'];

        // Preprocessing allows a binding provider to mutate a node before bindings are applied to it. For example it's
        // possible to insert new siblings after it, and/or replace the node with a different one. This can be used to
        // implement custom binding syntaxes, such as {{ value }} for string interpolation, or custom element types that
        // trigger insertion of <template> contents at that point in the document.
        if (preprocessNode) {
            while (currentChild = nextInQueue) {
                nextInQueue = ko.virtualElements.nextSibling(currentChild);
                preprocessNode.call(provider, currentChild);
            }
            // Reset nextInQueue for the next loop
            nextInQueue = ko.virtualElements.firstChild(elementOrVirtualElement);
        }

        while (currentChild = nextInQueue) {
            // Keep a record of the next child *before* applying bindings, in case the binding removes the current child from its position
            nextInQueue = ko.virtualElements.nextSibling(currentChild);
            applyBindingsToNodeAndDescendantsInternal(bindingContext, currentChild, bindingContextsMayDifferFromDomParentElement);
        }
    }

    function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
        var shouldBindDescendants = true;

        // Perf optimisation: Apply bindings only if...
        // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
        //     Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
        // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
        var isElement = (nodeVerified.nodeType === 1);
        if (isElement) // Workaround IE <= 8 HTML parsing weirdness
            ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);

        var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement)             // Case (1)
                               || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified);       // Case (2)
        if (shouldApplyBindings)
            shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];

        if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
            // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
            //  * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
            //    hence bindingContextsMayDifferFromDomParentElement is false
            //  * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
            //    skip over any number of intermediate virtual elements, any of which might define a custom binding context,
            //    hence bindingContextsMayDifferFromDomParentElement is true
            applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
        }
    }

    var boundElementDomDataKey = ko.utils.domData.nextKey();


    function topologicalSortBindings(bindings) {
        // Depth-first sort
        var result = [],                // The list of key/handler pairs that we will return
            bindingsConsidered = {},    // A temporary record of which bindings are already in 'result'
            cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
        ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
            if (!bindingsConsidered[bindingKey]) {
                var binding = ko['getBindingHandler'](bindingKey);
                if (binding) {
                    // First add dependencies (if any) of the current binding
                    if (binding['after']) {
                        cyclicDependencyStack.push(bindingKey);
                        ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
                            if (bindings[bindingDependencyKey]) {
                                if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
                                    throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
                                } else {
                                    pushBinding(bindingDependencyKey);
                                }
                            }
                        });
                        cyclicDependencyStack.length--;
                    }
                    // Next add the current binding
                    result.push({ key: bindingKey, handler: binding });
                }
                bindingsConsidered[bindingKey] = true;
            }
        });

        return result;
    }

    function applyBindingsToNodeInternal(node, sourceBindings, bindingContext, bindingContextMayDifferFromDomParentElement) {
        // Prevent multiple applyBindings calls for the same node, except when a binding value is specified
        var alreadyBound = ko.utils.domData.get(node, boundElementDomDataKey);
        if (!sourceBindings) {
            if (alreadyBound) {
                throw Error("You cannot apply bindings multiple times to the same element.");
            }
            ko.utils.domData.set(node, boundElementDomDataKey, true);
        }

        // Optimization: Don't store the binding context on this node if it's definitely the same as on node.parentNode, because
        // we can easily recover it just by scanning up the node's ancestors in the DOM
        // (note: here, parent node means "real DOM parent" not "virtual parent", as there's no O(1) way to find the virtual parent)
        if (!alreadyBound && bindingContextMayDifferFromDomParentElement)
            ko.storedBindingContextForNode(node, bindingContext);

        // Use bindings if given, otherwise fall back on asking the bindings provider to give us some bindings
        var bindings;
        if (sourceBindings && typeof sourceBindings !== 'function') {
            bindings = sourceBindings;
        } else {
            var provider = ko.bindingProvider['instance'],
                getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors;

            // Get the binding from the provider within a computed observable so that we can update the bindings whenever
            // the binding context is updated or if the binding provider accesses observables.
            var bindingsUpdater = ko.dependentObservable(
                function() {
                    bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
                    // Register a dependency on the binding context to support observable view models.
                    if (bindings && bindingContext._subscribable)
                        bindingContext._subscribable();
                    return bindings;
                },
                null, { disposeWhenNodeIsRemoved: node }
            );

            if (!bindings || !bindingsUpdater.isActive())
                bindingsUpdater = null;
        }

        var bindingHandlerThatControlsDescendantBindings;
        if (bindings) {
            // Return the value accessor for a given binding. When bindings are static (won't be updated because of a binding
            // context update), just return the value accessor from the binding. Otherwise, return a function that always gets
            // the latest binding value and registers a dependency on the binding updater.
            var getValueAccessor = bindingsUpdater
                ? function(bindingKey) {
                    return function() {
                        return evaluateValueAccessor(bindingsUpdater()[bindingKey]);
                    };
                } : function(bindingKey) {
                    return bindings[bindingKey];
                };

            // Use of allBindings as a function is maintained for backwards compatibility, but its use is deprecated
            function allBindings() {
                return ko.utils.objectMap(bindingsUpdater ? bindingsUpdater() : bindings, evaluateValueAccessor);
            }
            // The following is the 3.x allBindings API
            allBindings['get'] = function(key) {
                return bindings[key] && evaluateValueAccessor(getValueAccessor(key));
            };
            allBindings['has'] = function(key) {
                return key in bindings;
            };

            // First put the bindings into the right order
            var orderedBindings = topologicalSortBindings(bindings);

            // Go through the sorted bindings, calling init and update for each
            ko.utils.arrayForEach(orderedBindings, function(bindingKeyAndHandler) {
                // Note that topologicalSortBindings has already filtered out any nonexistent binding handlers,
                // so bindingKeyAndHandler.handler will always be nonnull.
                var handlerInitFn = bindingKeyAndHandler.handler["init"],
                    handlerUpdateFn = bindingKeyAndHandler.handler["update"],
                    bindingKey = bindingKeyAndHandler.key;

                if (node.nodeType === 8) {
                    validateThatBindingIsAllowedForVirtualElements(bindingKey);
                }

                try {
                    // Run init, ignoring any dependencies
                    if (typeof handlerInitFn == "function") {
                        ko.dependencyDetection.ignore(function() {
                            var initResult = handlerInitFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);

                            // If this binding handler claims to control descendant bindings, make a note of this
                            if (initResult && initResult['controlsDescendantBindings']) {
                                if (bindingHandlerThatControlsDescendantBindings !== undefined)
                                    throw new Error("Multiple bindings (" + bindingHandlerThatControlsDescendantBindings + " and " + bindingKey + ") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");
                                bindingHandlerThatControlsDescendantBindings = bindingKey;
                            }
                        });
                    }

                    // Run update in its own computed wrapper
                    if (typeof handlerUpdateFn == "function") {
                        ko.dependentObservable(
                            function() {
                                handlerUpdateFn(node, getValueAccessor(bindingKey), allBindings, bindingContext['$data'], bindingContext);
                            },
                            null,
                            { disposeWhenNodeIsRemoved: node }
                        );
                    }
                } catch (ex) {
                    ex.message = "Unable to process binding \"" + bindingKey + ": " + bindings[bindingKey] + "\"\nMessage: " + ex.message;
                    throw ex;
                }
            });
        }

        return {
            'shouldBindDescendants': bindingHandlerThatControlsDescendantBindings === undefined
        };
    };

    var storedBindingContextDomDataKey = ko.utils.domData.nextKey();
    ko.storedBindingContextForNode = function (node, bindingContext) {
        if (arguments.length == 2) {
            ko.utils.domData.set(node, storedBindingContextDomDataKey, bindingContext);
            if (bindingContext._subscribable)
                bindingContext._subscribable._addNode(node);
        } else {
            return ko.utils.domData.get(node, storedBindingContextDomDataKey);
        }
    }

    function getBindingContext(viewModelOrBindingContext) {
        return viewModelOrBindingContext && (viewModelOrBindingContext instanceof ko.bindingContext)
            ? viewModelOrBindingContext
            : new ko.bindingContext(viewModelOrBindingContext);
    }

    ko.applyBindingAccessorsToNode = function (node, bindings, viewModelOrBindingContext) {
        if (node.nodeType === 1) // If it's an element, workaround IE <= 8 HTML parsing weirdness
            ko.virtualElements.normaliseVirtualElementDomStructure(node);
        return applyBindingsToNodeInternal(node, bindings, getBindingContext(viewModelOrBindingContext), true);
    };

    ko.applyBindingsToNode = function (node, bindings, viewModelOrBindingContext) {
        var context = getBindingContext(viewModelOrBindingContext);
        return ko.applyBindingAccessorsToNode(node, makeBindingAccessors(bindings, context, node), context);
    };

    ko.applyBindingsToDescendants = function(viewModelOrBindingContext, rootNode) {
        if (rootNode.nodeType === 1 || rootNode.nodeType === 8)
            applyBindingsToDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
    };

    ko.applyBindings = function (viewModelOrBindingContext, rootNode) {
        // If jQuery is loaded after Knockout, we won't initially have access to it. So save it here.
        if (!jQueryInstance && window['jQuery']) {
            jQueryInstance = window['jQuery'];
        }

        if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
            throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
        rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional

        applyBindingsToNodeAndDescendantsInternal(getBindingContext(viewModelOrBindingContext), rootNode, true);
    };

    // Retrieving binding context from arbitrary nodes
    ko.contextFor = function(node) {
        // We can only do something meaningful for elements and comment nodes (in particular, not text nodes, as IE can't store domdata for them)
        switch (node.nodeType) {
            case 1:
            case 8:
                var context = ko.storedBindingContextForNode(node);
                if (context) return context;
                if (node.parentNode) return ko.contextFor(node.parentNode);
                break;
        }
        return undefined;
    };
    ko.dataFor = function(node) {
        var context = ko.contextFor(node);
        return context ? context['$data'] : undefined;
    };

    ko.exportSymbol('bindingHandlers', ko.bindingHandlers);
    ko.exportSymbol('applyBindings', ko.applyBindings);
    ko.exportSymbol('applyBindingsToDescendants', ko.applyBindingsToDescendants);
    ko.exportSymbol('applyBindingAccessorsToNode', ko.applyBindingAccessorsToNode);
    ko.exportSymbol('applyBindingsToNode', ko.applyBindingsToNode);
    ko.exportSymbol('contextFor', ko.contextFor);
    ko.exportSymbol('dataFor', ko.dataFor);
})();
(function(undefined) {
    var loadingSubscribablesCache = {}, // Tracks component loads that are currently in flight
        loadedDefinitionsCache = {};    // Tracks component loads that have already completed

    ko.components = {
        get: function(componentName, callback) {
            var cachedDefinition = getObjectOwnProperty(loadedDefinitionsCache, componentName);
            if (cachedDefinition) {
                // It's already loaded and cached. Reuse the same definition object.
                // Note that for API consistency, even cache hits complete asynchronously by default.
                // You can bypass this by putting synchronous:true on your component config.
                if (cachedDefinition.isSynchronousComponent) {
                    ko.dependencyDetection.ignore(function() { // See comment in loaderRegistryBehaviors.js for reasoning
                        callback(cachedDefinition.definition);
                    });
                } else {
                    ko.tasks.schedule(function() { callback(cachedDefinition.definition); });
                }
            } else {
                // Join the loading process that is already underway, or start a new one.
                loadComponentAndNotify(componentName, callback);
            }
        },

        clearCachedDefinition: function(componentName) {
            delete loadedDefinitionsCache[componentName];
        },

        _getFirstResultFromLoaders: getFirstResultFromLoaders
    };

    function getObjectOwnProperty(obj, propName) {
        return obj.hasOwnProperty(propName) ? obj[propName] : undefined;
    }

    function loadComponentAndNotify(componentName, callback) {
        var subscribable = getObjectOwnProperty(loadingSubscribablesCache, componentName),
            completedAsync;
        if (!subscribable) {
            // It's not started loading yet. Start loading, and when it's done, move it to loadedDefinitionsCache.
            subscribable = loadingSubscribablesCache[componentName] = new ko.subscribable();
            subscribable.subscribe(callback);

            beginLoadingComponent(componentName, function(definition, config) {
                var isSynchronousComponent = !!(config && config['synchronous']);
                loadedDefinitionsCache[componentName] = { definition: definition, isSynchronousComponent: isSynchronousComponent };
                delete loadingSubscribablesCache[componentName];

                // For API consistency, all loads complete asynchronously. However we want to avoid
                // adding an extra task schedule if it's unnecessary (i.e., the completion is already
                // async).
                //
                // You can bypass the 'always asynchronous' feature by putting the synchronous:true
                // flag on your component configuration when you register it.
                if (completedAsync || isSynchronousComponent) {
                    // Note that notifySubscribers ignores any dependencies read within the callback.
                    // See comment in loaderRegistryBehaviors.js for reasoning
                    subscribable['notifySubscribers'](definition);
                } else {
                    ko.tasks.schedule(function() {
                        subscribable['notifySubscribers'](definition);
                    });
                }
            });
            completedAsync = true;
        } else {
            subscribable.subscribe(callback);
        }
    }

    function beginLoadingComponent(componentName, callback) {
        getFirstResultFromLoaders('getConfig', [componentName], function(config) {
            if (config) {
                // We have a config, so now load its definition
                getFirstResultFromLoaders('loadComponent', [componentName, config], function(definition) {
                    callback(definition, config);
                });
            } else {
                // The component has no config - it's unknown to all the loaders.
                // Note that this is not an error (e.g., a module loading error) - that would abort the
                // process and this callback would not run. For this callback to run, all loaders must
                // have confirmed they don't know about this component.
                callback(null, null);
            }
        });
    }

    function getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders) {
        // On the first call in the stack, start with the full set of loaders
        if (!candidateLoaders) {
            candidateLoaders = ko.components['loaders'].slice(0); // Use a copy, because we'll be mutating this array
        }

        // Try the next candidate
        var currentCandidateLoader = candidateLoaders.shift();
        if (currentCandidateLoader) {
            var methodInstance = currentCandidateLoader[methodName];
            if (methodInstance) {
                var wasAborted = false,
                    synchronousReturnValue = methodInstance.apply(currentCandidateLoader, argsExceptCallback.concat(function(result) {
                        if (wasAborted) {
                            callback(null);
                        } else if (result !== null) {
                            // This candidate returned a value. Use it.
                            callback(result);
                        } else {
                            // Try the next candidate
                            getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
                        }
                    }));

                // Currently, loaders may not return anything synchronously. This leaves open the possibility
                // that we'll extend the API to support synchronous return values in the future. It won't be
                // a breaking change, because currently no loader is allowed to return anything except undefined.
                if (synchronousReturnValue !== undefined) {
                    wasAborted = true;

                    // Method to suppress exceptions will remain undocumented. This is only to keep
                    // KO's specs running tidily, since we can observe the loading got aborted without
                    // having exceptions cluttering up the console too.
                    if (!currentCandidateLoader['suppressLoaderExceptions']) {
                        throw new Error('Component loaders must supply values by invoking the callback, not by returning values synchronously.');
                    }
                }
            } else {
                // This candidate doesn't have the relevant handler. Synchronously move on to the next one.
                getFirstResultFromLoaders(methodName, argsExceptCallback, callback, candidateLoaders);
            }
        } else {
            // No candidates returned a value
            callback(null);
        }
    }

    // Reference the loaders via string name so it's possible for developers
    // to replace the whole array by assigning to ko.components.loaders
    ko.components['loaders'] = [];

    ko.exportSymbol('components', ko.components);
    ko.exportSymbol('components.get', ko.components.get);
    ko.exportSymbol('components.clearCachedDefinition', ko.components.clearCachedDefinition);
})();
(function(undefined) {

    // The default loader is responsible for two things:
    // 1. Maintaining the default in-memory registry of component configuration objects
    //    (i.e., the thing you're writing to when you call ko.components.register(someName, ...))
    // 2. Answering requests for components by fetching configuration objects
    //    from that default in-memory registry and resolving them into standard
    //    component definition objects (of the form { createViewModel: ..., template: ... })
    // Custom loaders may override either of these facilities, i.e.,
    // 1. To supply configuration objects from some other source (e.g., conventions)
    // 2. Or, to resolve configuration objects by loading viewmodels/templates via arbitrary logic.

    var defaultConfigRegistry = {};

    ko.components.register = function(componentName, config) {
        if (!config) {
            throw new Error('Invalid configuration for ' + componentName);
        }

        if (ko.components.isRegistered(componentName)) {
            throw new Error('Component ' + componentName + ' is already registered');
        }

        defaultConfigRegistry[componentName] = config;
    };

    ko.components.isRegistered = function(componentName) {
        return defaultConfigRegistry.hasOwnProperty(componentName);
    };

    ko.components.unregister = function(componentName) {
        delete defaultConfigRegistry[componentName];
        ko.components.clearCachedDefinition(componentName);
    };

    ko.components.defaultLoader = {
        'getConfig': function(componentName, callback) {
            var result = defaultConfigRegistry.hasOwnProperty(componentName)
                ? defaultConfigRegistry[componentName]
                : null;
            callback(result);
        },

        'loadComponent': function(componentName, config, callback) {
            var errorCallback = makeErrorCallback(componentName);
            possiblyGetConfigFromAmd(errorCallback, config, function(loadedConfig) {
                resolveConfig(componentName, errorCallback, loadedConfig, callback);
            });
        },

        'loadTemplate': function(componentName, templateConfig, callback) {
            resolveTemplate(makeErrorCallback(componentName), templateConfig, callback);
        },

        'loadViewModel': function(componentName, viewModelConfig, callback) {
            resolveViewModel(makeErrorCallback(componentName), viewModelConfig, callback);
        }
    };

    var createViewModelKey = 'createViewModel';

    // Takes a config object of the form { template: ..., viewModel: ... }, and asynchronously convert it
    // into the standard component definition format:
    //    { template: <ArrayOfDomNodes>, createViewModel: function(params, componentInfo) { ... } }.
    // Since both template and viewModel may need to be resolved asynchronously, both tasks are performed
    // in parallel, and the results joined when both are ready. We don't depend on any promises infrastructure,
    // so this is implemented manually below.
    function resolveConfig(componentName, errorCallback, config, callback) {
        var result = {},
            makeCallBackWhenZero = 2,
            tryIssueCallback = function() {
                if (--makeCallBackWhenZero === 0) {
                    callback(result);
                }
            },
            templateConfig = config['template'],
            viewModelConfig = config['viewModel'];

        if (templateConfig) {
            possiblyGetConfigFromAmd(errorCallback, templateConfig, function(loadedConfig) {
                ko.components._getFirstResultFromLoaders('loadTemplate', [componentName, loadedConfig], function(resolvedTemplate) {
                    result['template'] = resolvedTemplate;
                    tryIssueCallback();
                });
            });
        } else {
            tryIssueCallback();
        }

        if (viewModelConfig) {
            possiblyGetConfigFromAmd(errorCallback, viewModelConfig, function(loadedConfig) {
                ko.components._getFirstResultFromLoaders('loadViewModel', [componentName, loadedConfig], function(resolvedViewModel) {
                    result[createViewModelKey] = resolvedViewModel;
                    tryIssueCallback();
                });
            });
        } else {
            tryIssueCallback();
        }
    }

    function resolveTemplate(errorCallback, templateConfig, callback) {
        if (typeof templateConfig === 'string') {
            // Markup - parse it
            callback(ko.utils.parseHtmlFragment(templateConfig));
        } else if (templateConfig instanceof Array) {
            // Assume already an array of DOM nodes - pass through unchanged
            callback(templateConfig);
        } else if (isDocumentFragment(templateConfig)) {
            // Document fragment - use its child nodes
            callback(ko.utils.makeArray(templateConfig.childNodes));
        } else if (templateConfig['element']) {
            var element = templateConfig['element'];
            if (isDomElement(element)) {
                // Element instance - copy its child nodes
                callback(cloneNodesFromTemplateSourceElement(element));
            } else if (typeof element === 'string') {
                // Element ID - find it, then copy its child nodes
                var elemInstance = document.getElementById(element);
                if (elemInstance) {
                    callback(cloneNodesFromTemplateSourceElement(elemInstance));
                } else {
                    errorCallback('Cannot find element with ID ' + element);
                }
            } else {
                errorCallback('Unknown element type: ' + element);
            }
        } else {
            errorCallback('Unknown template value: ' + templateConfig);
        }
    }

    function resolveViewModel(errorCallback, viewModelConfig, callback) {
        if (typeof viewModelConfig === 'function') {
            // Constructor - convert to standard factory function format
            // By design, this does *not* supply componentInfo to the constructor, as the intent is that
            // componentInfo contains non-viewmodel data (e.g., the component's element) that should only
            // be used in factory functions, not viewmodel constructors.
            callback(function (params /*, componentInfo */) {
                return new viewModelConfig(params);
            });
        } else if (typeof viewModelConfig[createViewModelKey] === 'function') {
            // Already a factory function - use it as-is
            callback(viewModelConfig[createViewModelKey]);
        } else if ('instance' in viewModelConfig) {
            // Fixed object instance - promote to createViewModel format for API consistency
            var fixedInstance = viewModelConfig['instance'];
            callback(function (params, componentInfo) {
                return fixedInstance;
            });
        } else if ('viewModel' in viewModelConfig) {
            // Resolved AMD module whose value is of the form { viewModel: ... }
            resolveViewModel(errorCallback, viewModelConfig['viewModel'], callback);
        } else {
            errorCallback('Unknown viewModel value: ' + viewModelConfig);
        }
    }

    function cloneNodesFromTemplateSourceElement(elemInstance) {
        switch (ko.utils.tagNameLower(elemInstance)) {
            case 'script':
                return ko.utils.parseHtmlFragment(elemInstance.text);
            case 'textarea':
                return ko.utils.parseHtmlFragment(elemInstance.value);
            case 'template':
                // For browsers with proper <template> element support (i.e., where the .content property
                // gives a document fragment), use that document fragment.
                if (isDocumentFragment(elemInstance.content)) {
                    return ko.utils.cloneNodes(elemInstance.content.childNodes);
                }
        }

        // Regular elements such as <div>, and <template> elements on old browsers that don't really
        // understand <template> and just treat it as a regular container
        return ko.utils.cloneNodes(elemInstance.childNodes);
    }

    function isDomElement(obj) {
        if (window['HTMLElement']) {
            return obj instanceof HTMLElement;
        } else {
            return obj && obj.tagName && obj.nodeType === 1;
        }
    }

    function isDocumentFragment(obj) {
        if (window['DocumentFragment']) {
            return obj instanceof DocumentFragment;
        } else {
            return obj && obj.nodeType === 11;
        }
    }

    function possiblyGetConfigFromAmd(errorCallback, config, callback) {
        if (typeof config['require'] === 'string') {
            // The config is the value of an AMD module
            if (amdRequire || window['require']) {
                (amdRequire || window['require'])([config['require']], callback);
            } else {
                errorCallback('Uses require, but no AMD loader is present');
            }
        } else {
            callback(config);
        }
    }

    function makeErrorCallback(componentName) {
        return function (message) {
            throw new Error('Component \'' + componentName + '\': ' + message);
        };
    }

    ko.exportSymbol('components.register', ko.components.register);
    ko.exportSymbol('components.isRegistered', ko.components.isRegistered);
    ko.exportSymbol('components.unregister', ko.components.unregister);

    // Expose the default loader so that developers can directly ask it for configuration
    // or to resolve configuration
    ko.exportSymbol('components.defaultLoader', ko.components.defaultLoader);

    // By default, the default loader is the only registered component loader
    ko.components['loaders'].push(ko.components.defaultLoader);

    // Privately expose the underlying config registry for use in old-IE shim
    ko.components._allRegisteredComponents = defaultConfigRegistry;
})();
(function (undefined) {
    // Overridable API for determining which component name applies to a given node. By overriding this,
    // you can for example map specific tagNames to components that are not preregistered.
    ko.components['getComponentNameForNode'] = function(node) {
        var tagNameLower = ko.utils.tagNameLower(node);
        if (ko.components.isRegistered(tagNameLower)) {
            // Try to determine that this node can be considered a *custom* element; see https://github.com/knockout/knockout/issues/1603
            if (tagNameLower.indexOf('-') != -1 || ('' + node) == "[object HTMLUnknownElement]" || (ko.utils.ieVersion <= 8 && node.tagName === tagNameLower)) {
                return tagNameLower;
            }
        }
    };

    ko.components.addBindingsForCustomElement = function(allBindings, node, bindingContext, valueAccessors) {
        // Determine if it's really a custom element matching a component
        if (node.nodeType === 1) {
            var componentName = ko.components['getComponentNameForNode'](node);
            if (componentName) {
                // It does represent a component, so add a component binding for it
                allBindings = allBindings || {};

                if (allBindings['component']) {
                    // Avoid silently overwriting some other 'component' binding that may already be on the element
                    throw new Error('Cannot use the "component" binding on a custom element matching a component');
                }

                var componentBindingValue = { 'name': componentName, 'params': getComponentParamsFromCustomElement(node, bindingContext) };

                allBindings['component'] = valueAccessors
                    ? function() { return componentBindingValue; }
                    : componentBindingValue;
            }
        }

        return allBindings;
    }

    var nativeBindingProviderInstance = new ko.bindingProvider();

    function getComponentParamsFromCustomElement(elem, bindingContext) {
        var paramsAttribute = elem.getAttribute('params');

        if (paramsAttribute) {
            var params = nativeBindingProviderInstance['parseBindingsString'](paramsAttribute, bindingContext, elem, { 'valueAccessors': true, 'bindingParams': true }),
                rawParamComputedValues = ko.utils.objectMap(params, function(paramValue, paramName) {
                    return ko.computed(paramValue, null, { disposeWhenNodeIsRemoved: elem });
                }),
                result = ko.utils.objectMap(rawParamComputedValues, function(paramValueComputed, paramName) {
                    var paramValue = paramValueComputed.peek();
                    // Does the evaluation of the parameter value unwrap any observables?
                    if (!paramValueComputed.isActive()) {
                        // No it doesn't, so there's no need for any computed wrapper. Just pass through the supplied value directly.
                        // Example: "someVal: firstName, age: 123" (whether or not firstName is an observable/computed)
                        return paramValue;
                    } else {
                        // Yes it does. Supply a computed property that unwraps both the outer (binding expression)
                        // level of observability, and any inner (resulting model value) level of observability.
                        // This means the component doesn't have to worry about multiple unwrapping. If the value is a
                        // writable observable, the computed will also be writable and pass the value on to the observable.
                        return ko.computed({
                            'read': function() {
                                return ko.utils.unwrapObservable(paramValueComputed());
                            },
                            'write': ko.isWriteableObservable(paramValue) && function(value) {
                                paramValueComputed()(value);
                            },
                            disposeWhenNodeIsRemoved: elem
                        });
                    }
                });

            // Give access to the raw computeds, as long as that wouldn't overwrite any custom param also called '$raw'
            // This is in case the developer wants to react to outer (binding) observability separately from inner
            // (model value) observability, or in case the model value observable has subobservables.
            if (!result.hasOwnProperty('$raw')) {
                result['$raw'] = rawParamComputedValues;
            }

            return result;
        } else {
            // For consistency, absence of a "params" attribute is treated the same as the presence of
            // any empty one. Otherwise component viewmodels need special code to check whether or not
            // 'params' or 'params.$raw' is null/undefined before reading subproperties, which is annoying.
            return { '$raw': {} };
        }
    }

    // --------------------------------------------------------------------------------
    // Compatibility code for older (pre-HTML5) IE browsers

    if (ko.utils.ieVersion < 9) {
        // Whenever you preregister a component, enable it as a custom element in the current document
        ko.components['register'] = (function(originalFunction) {
            return function(componentName) {
                document.createElement(componentName); // Allows IE<9 to parse markup containing the custom element
                return originalFunction.apply(this, arguments);
            }
        })(ko.components['register']);

        // Whenever you create a document fragment, enable all preregistered component names as custom elements
        // This is needed to make innerShiv/jQuery HTML parsing correctly handle the custom elements
        document.createDocumentFragment = (function(originalFunction) {
            return function() {
                var newDocFrag = originalFunction(),
                    allComponents = ko.components._allRegisteredComponents;
                for (var componentName in allComponents) {
                    if (allComponents.hasOwnProperty(componentName)) {
                        newDocFrag.createElement(componentName);
                    }
                }
                return newDocFrag;
            };
        })(document.createDocumentFragment);
    }
})();(function(undefined) {

    var componentLoadingOperationUniqueId = 0;

    ko.bindingHandlers['component'] = {
        'init': function(element, valueAccessor, ignored1, ignored2, bindingContext) {
            var currentViewModel,
                currentLoadingOperationId,
                disposeAssociatedComponentViewModel = function () {
                    var currentViewModelDispose = currentViewModel && currentViewModel['dispose'];
                    if (typeof currentViewModelDispose === 'function') {
                        currentViewModelDispose.call(currentViewModel);
                    }
                    currentViewModel = null;
                    // Any in-flight loading operation is no longer relevant, so make sure we ignore its completion
                    currentLoadingOperationId = null;
                },
                originalChildNodes = ko.utils.makeArray(ko.virtualElements.childNodes(element));

            ko.utils.domNodeDisposal.addDisposeCallback(element, disposeAssociatedComponentViewModel);

            ko.computed(function () {
                var value = ko.utils.unwrapObservable(valueAccessor()),
                    componentName, componentParams;

                if (typeof value === 'string') {
                    componentName = value;
                } else {
                    componentName = ko.utils.unwrapObservable(value['name']);
                    componentParams = ko.utils.unwrapObservable(value['params']);
                }

                if (!componentName) {
                    throw new Error('No component name specified');
                }

                var loadingOperationId = currentLoadingOperationId = ++componentLoadingOperationUniqueId;
                ko.components.get(componentName, function(componentDefinition) {
                    // If this is not the current load operation for this element, ignore it.
                    if (currentLoadingOperationId !== loadingOperationId) {
                        return;
                    }

                    // Clean up previous state
                    disposeAssociatedComponentViewModel();

                    // Instantiate and bind new component. Implicitly this cleans any old DOM nodes.
                    if (!componentDefinition) {
                        throw new Error('Unknown component \'' + componentName + '\'');
                    }
                    cloneTemplateIntoElement(componentName, componentDefinition, element);
                    var componentViewModel = createViewModel(componentDefinition, element, originalChildNodes, componentParams),
                        childBindingContext = bindingContext['createChildContext'](componentViewModel, /* dataItemAlias */ undefined, function(ctx) {
                            ctx['$component'] = componentViewModel;
                            ctx['$componentTemplateNodes'] = originalChildNodes;
                        });
                    currentViewModel = componentViewModel;
                    ko.applyBindingsToDescendants(childBindingContext, element);
                });
            }, null, { disposeWhenNodeIsRemoved: element });

            return { 'controlsDescendantBindings': true };
        }
    };

    ko.virtualElements.allowedBindings['component'] = true;

    function cloneTemplateIntoElement(componentName, componentDefinition, element) {
        var template = componentDefinition['template'];
        if (!template) {
            throw new Error('Component \'' + componentName + '\' has no template');
        }

        var clonedNodesArray = ko.utils.cloneNodes(template);
        ko.virtualElements.setDomNodeChildren(element, clonedNodesArray);
    }

    function createViewModel(componentDefinition, element, originalChildNodes, componentParams) {
        var componentViewModelFactory = componentDefinition['createViewModel'];
        return componentViewModelFactory
            ? componentViewModelFactory.call(componentDefinition, componentParams, { 'element': element, 'templateNodes': originalChildNodes })
            : componentParams; // Template-only component
    }

})();
var attrHtmlToJavascriptMap = { 'class': 'className', 'for': 'htmlFor' };
ko.bindingHandlers['attr'] = {
    'update': function(element, valueAccessor, allBindings) {
        var value = ko.utils.unwrapObservable(valueAccessor()) || {};
        ko.utils.objectForEach(value, function(attrName, attrValue) {
            attrValue = ko.utils.unwrapObservable(attrValue);

            // To cover cases like "attr: { checked:someProp }", we want to remove the attribute entirely
            // when someProp is a "no value"-like value (strictly null, false, or undefined)
            // (because the absence of the "checked" attr is how to mark an element as not checked, etc.)
            var toRemove = (attrValue === false) || (attrValue === null) || (attrValue === undefined);
            if (toRemove)
                element.removeAttribute(attrName);

            // In IE <= 7 and IE8 Quirks Mode, you have to use the Javascript property name instead of the
            // HTML attribute name for certain attributes. IE8 Standards Mode supports the correct behavior,
            // but instead of figuring out the mode, we'll just set the attribute through the Javascript
            // property for IE <= 8.
            if (ko.utils.ieVersion <= 8 && attrName in attrHtmlToJavascriptMap) {
                attrName = attrHtmlToJavascriptMap[attrName];
                if (toRemove)
                    element.removeAttribute(attrName);
                else
                    element[attrName] = attrValue;
            } else if (!toRemove) {
                element.setAttribute(attrName, attrValue.toString());
            }

            // Treat "name" specially - although you can think of it as an attribute, it also needs
            // special handling on older versions of IE (https://github.com/SteveSanderson/knockout/pull/333)
            // Deliberately being case-sensitive here because XHTML would regard "Name" as a different thing
            // entirely, and there's no strong reason to allow for such casing in HTML.
            if (attrName === "name") {
                ko.utils.setElementName(element, toRemove ? "" : attrValue.toString());
            }
        });
    }
};
(function() {

ko.bindingHandlers['checked'] = {
    'after': ['value', 'attr'],
    'init': function (element, valueAccessor, allBindings) {
        var checkedValue = ko.pureComputed(function() {
            // Treat "value" like "checkedValue" when it is included with "checked" binding
            if (allBindings['has']('checkedValue')) {
                return ko.utils.unwrapObservable(allBindings.get('checkedValue'));
            } else if (allBindings['has']('value')) {
                return ko.utils.unwrapObservable(allBindings.get('value'));
            }

            return element.value;
        });

        function updateModel() {
            // This updates the model value from the view value.
            // It runs in response to DOM events (click) and changes in checkedValue.
            var isChecked = element.checked,
                elemValue = useCheckedValue ? checkedValue() : isChecked;

            // When we're first setting up this computed, don't change any model state.
            if (ko.computedContext.isInitial()) {
                return;
            }

            // We can ignore unchecked radio buttons, because some other radio
            // button will be getting checked, and that one can take care of updating state.
            if (isRadio && !isChecked) {
                return;
            }

            var modelValue = ko.dependencyDetection.ignore(valueAccessor);
            if (valueIsArray) {
                var writableValue = rawValueIsNonArrayObservable ? modelValue.peek() : modelValue;
                if (oldElemValue !== elemValue) {
                    // When we're responding to the checkedValue changing, and the element is
                    // currently checked, replace the old elem value with the new elem value
                    // in the model array.
                    if (isChecked) {
                        ko.utils.addOrRemoveItem(writableValue, elemValue, true);
                        ko.utils.addOrRemoveItem(writableValue, oldElemValue, false);
                    }

                    oldElemValue = elemValue;
                } else {
                    // When we're responding to the user having checked/unchecked a checkbox,
                    // add/remove the element value to the model array.
                    ko.utils.addOrRemoveItem(writableValue, elemValue, isChecked);
                }
                if (rawValueIsNonArrayObservable && ko.isWriteableObservable(modelValue)) {
                    modelValue(writableValue);
                }
            } else {
                ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'checked', elemValue, true);
            }
        };

        function updateView() {
            // This updates the view value from the model value.
            // It runs in response to changes in the bound (checked) value.
            var modelValue = ko.utils.unwrapObservable(valueAccessor());

            if (valueIsArray) {
                // When a checkbox is bound to an array, being checked represents its value being present in that array
                element.checked = ko.utils.arrayIndexOf(modelValue, checkedValue()) >= 0;
            } else if (isCheckbox) {
                // When a checkbox is bound to any other value (not an array), being checked represents the value being trueish
                element.checked = modelValue;
            } else {
                // For radio buttons, being checked means that the radio button's value corresponds to the model value
                element.checked = (checkedValue() === modelValue);
            }
        };

        var isCheckbox = element.type == "checkbox",
            isRadio = element.type == "radio";

        // Only bind to check boxes and radio buttons
        if (!isCheckbox && !isRadio) {
            return;
        }

        var rawValue = valueAccessor(),
            valueIsArray = isCheckbox && (ko.utils.unwrapObservable(rawValue) instanceof Array),
            rawValueIsNonArrayObservable = !(valueIsArray && rawValue.push && rawValue.splice),
            oldElemValue = valueIsArray ? checkedValue() : undefined,
            useCheckedValue = isRadio || valueIsArray;

        // IE 6 won't allow radio buttons to be selected unless they have a name
        if (isRadio && !element.name)
            ko.bindingHandlers['uniqueName']['init'](element, function() { return true });

        // Set up two computeds to update the binding:

        // The first responds to changes in the checkedValue value and to element clicks
        ko.computed(updateModel, null, { disposeWhenNodeIsRemoved: element });
        ko.utils.registerEventHandler(element, "click", updateModel);

        // The second responds to changes in the model value (the one associated with the checked binding)
        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });

        rawValue = undefined;
    }
};
ko.expressionRewriting.twoWayBindings['checked'] = true;

ko.bindingHandlers['checkedValue'] = {
    'update': function (element, valueAccessor) {
        element.value = ko.utils.unwrapObservable(valueAccessor());
    }
};

})();var classesWrittenByBindingKey = '__ko__cssValue';
ko.bindingHandlers['css'] = {
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value !== null && typeof value == "object") {
            ko.utils.objectForEach(value, function(className, shouldHaveClass) {
                shouldHaveClass = ko.utils.unwrapObservable(shouldHaveClass);
                ko.utils.toggleDomNodeCssClass(element, className, shouldHaveClass);
            });
        } else {
            value = ko.utils.stringTrim(String(value || '')); // Make sure we don't try to store or set a non-string value
            ko.utils.toggleDomNodeCssClass(element, element[classesWrittenByBindingKey], false);
            element[classesWrittenByBindingKey] = value;
            ko.utils.toggleDomNodeCssClass(element, value, true);
        }
    }
};
ko.bindingHandlers['enable'] = {
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        if (value && element.disabled)
            element.removeAttribute("disabled");
        else if ((!value) && (!element.disabled))
            element.disabled = true;
    }
};

ko.bindingHandlers['disable'] = {
    'update': function (element, valueAccessor) {
        ko.bindingHandlers['enable']['update'](element, function() { return !ko.utils.unwrapObservable(valueAccessor()) });
    }
};
// For certain common events (currently just 'click'), allow a simplified data-binding syntax
// e.g. click:handler instead of the usual full-length event:{click:handler}
function makeEventHandlerShortcut(eventName) {
    ko.bindingHandlers[eventName] = {
        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var newValueAccessor = function () {
                var result = {};
                result[eventName] = valueAccessor();
                return result;
            };
            return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext);
        }
    }
}

ko.bindingHandlers['event'] = {
    'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        var eventsToHandle = valueAccessor() || {};
        ko.utils.objectForEach(eventsToHandle, function(eventName) {
            if (typeof eventName == "string") {
                ko.utils.registerEventHandler(element, eventName, function (event) {
                    var handlerReturnValue;
                    var handlerFunction = valueAccessor()[eventName];
                    if (!handlerFunction)
                        return;

                    try {
                        // Take all the event args, and prefix with the viewmodel
                        var argsForHandler = ko.utils.makeArray(arguments);
                        viewModel = bindingContext['$data'];
                        argsForHandler.unshift(viewModel);
                        handlerReturnValue = handlerFunction.apply(viewModel, argsForHandler);
                    } finally {
                        if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
                            if (event.preventDefault)
                                event.preventDefault();
                            else
                                event.returnValue = false;
                        }
                    }

                    var bubble = allBindings.get(eventName + 'Bubble') !== false;
                    if (!bubble) {
                        event.cancelBubble = true;
                        if (event.stopPropagation)
                            event.stopPropagation();
                    }
                });
            }
        });
    }
};
// "foreach: someExpression" is equivalent to "template: { foreach: someExpression }"
// "foreach: { data: someExpression, afterAdd: myfn }" is equivalent to "template: { foreach: someExpression, afterAdd: myfn }"
ko.bindingHandlers['foreach'] = {
    makeTemplateValueAccessor: function(valueAccessor) {
        return function() {
            var modelValue = valueAccessor(),
                unwrappedValue = ko.utils.peekObservable(modelValue);    // Unwrap without setting a dependency here

            // If unwrappedValue is the array, pass in the wrapped value on its own
            // The value will be unwrapped and tracked within the template binding
            // (See https://github.com/SteveSanderson/knockout/issues/523)
            if ((!unwrappedValue) || typeof unwrappedValue.length == "number")
                return { 'foreach': modelValue, 'templateEngine': ko.nativeTemplateEngine.instance };

            // If unwrappedValue.data is the array, preserve all relevant options and unwrap again value so we get updates
            ko.utils.unwrapObservable(modelValue);
            return {
                'foreach': unwrappedValue['data'],
                'as': unwrappedValue['as'],
                'includeDestroyed': unwrappedValue['includeDestroyed'],
                'afterAdd': unwrappedValue['afterAdd'],
                'beforeRemove': unwrappedValue['beforeRemove'],
                'afterRender': unwrappedValue['afterRender'],
                'beforeMove': unwrappedValue['beforeMove'],
                'afterMove': unwrappedValue['afterMove'],
                'templateEngine': ko.nativeTemplateEngine.instance
            };
        };
    },
    'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        return ko.bindingHandlers['template']['init'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor));
    },
    'update': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        return ko.bindingHandlers['template']['update'](element, ko.bindingHandlers['foreach'].makeTemplateValueAccessor(valueAccessor), allBindings, viewModel, bindingContext);
    }
};
ko.expressionRewriting.bindingRewriteValidators['foreach'] = false; // Can't rewrite control flow bindings
ko.virtualElements.allowedBindings['foreach'] = true;
var hasfocusUpdatingProperty = '__ko_hasfocusUpdating';
var hasfocusLastValue = '__ko_hasfocusLastValue';
ko.bindingHandlers['hasfocus'] = {
    'init': function(element, valueAccessor, allBindings) {
        var handleElementFocusChange = function(isFocused) {
            // Where possible, ignore which event was raised and determine focus state using activeElement,
            // as this avoids phantom focus/blur events raised when changing tabs in modern browsers.
            // However, not all KO-targeted browsers (Firefox 2) support activeElement. For those browsers,
            // prevent a loss of focus when changing tabs/windows by setting a flag that prevents hasfocus
            // from calling 'blur()' on the element when it loses focus.
            // Discussion at https://github.com/SteveSanderson/knockout/pull/352
            element[hasfocusUpdatingProperty] = true;
            var ownerDoc = element.ownerDocument;
            if ("activeElement" in ownerDoc) {
                var active;
                try {
                    active = ownerDoc.activeElement;
                } catch(e) {
                    // IE9 throws if you access activeElement during page load (see issue #703)
                    active = ownerDoc.body;
                }
                isFocused = (active === element);
            }
            var modelValue = valueAccessor();
            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'hasfocus', isFocused, true);

            //cache the latest value, so we can avoid unnecessarily calling focus/blur in the update function
            element[hasfocusLastValue] = isFocused;
            element[hasfocusUpdatingProperty] = false;
        };
        var handleElementFocusIn = handleElementFocusChange.bind(null, true);
        var handleElementFocusOut = handleElementFocusChange.bind(null, false);

        ko.utils.registerEventHandler(element, "focus", handleElementFocusIn);
        ko.utils.registerEventHandler(element, "focusin", handleElementFocusIn); // For IE
        ko.utils.registerEventHandler(element, "blur",  handleElementFocusOut);
        ko.utils.registerEventHandler(element, "focusout",  handleElementFocusOut); // For IE
    },
    'update': function(element, valueAccessor) {
        var value = !!ko.utils.unwrapObservable(valueAccessor());

        if (!element[hasfocusUpdatingProperty] && element[hasfocusLastValue] !== value) {
            value ? element.focus() : element.blur();

            // In IE, the blur method doesn't always cause the element to lose focus (for example, if the window is not in focus).
            // Setting focus to the body element does seem to be reliable in IE, but should only be used if we know that the current
            // element was focused already.
            if (!value && element[hasfocusLastValue]) {
                element.ownerDocument.body.focus();
            }

            // For IE, which doesn't reliably fire "focus" or "blur" events synchronously
            ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, value ? "focusin" : "focusout"]);
        }
    }
};
ko.expressionRewriting.twoWayBindings['hasfocus'] = true;

ko.bindingHandlers['hasFocus'] = ko.bindingHandlers['hasfocus']; // Make "hasFocus" an alias
ko.expressionRewriting.twoWayBindings['hasFocus'] = true;
ko.bindingHandlers['html'] = {
    'init': function() {
        // Prevent binding on the dynamically-injected HTML (as developers are unlikely to expect that, and it has security implications)
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor) {
        // setHtml will unwrap the value if needed
        ko.utils.setHtml(element, valueAccessor());
    }
};
// Makes a binding like with or if
function makeWithIfBinding(bindingKey, isWith, isNot, makeContextCallback) {
    ko.bindingHandlers[bindingKey] = {
        'init': function(element, valueAccessor, allBindings, viewModel, bindingContext) {
            var didDisplayOnLastUpdate,
                savedNodes;
            ko.computed(function() {
                var dataValue = ko.utils.unwrapObservable(valueAccessor()),
                    shouldDisplay = !isNot !== !dataValue, // equivalent to isNot ? !dataValue : !!dataValue
                    isFirstRender = !savedNodes,
                    needsRefresh = isFirstRender || isWith || (shouldDisplay !== didDisplayOnLastUpdate);

                if (needsRefresh) {
                    // Save a copy of the inner nodes on the initial update, but only if we have dependencies.
                    if (isFirstRender && ko.computedContext.getDependenciesCount()) {
                        savedNodes = ko.utils.cloneNodes(ko.virtualElements.childNodes(element), true /* shouldCleanNodes */);
                    }

                    if (shouldDisplay) {
                        if (!isFirstRender) {
                            ko.virtualElements.setDomNodeChildren(element, ko.utils.cloneNodes(savedNodes));
                        }
                        ko.applyBindingsToDescendants(makeContextCallback ? makeContextCallback(bindingContext, dataValue) : bindingContext, element);
                    } else {
                        ko.virtualElements.emptyNode(element);
                    }

                    didDisplayOnLastUpdate = shouldDisplay;
                }
            }, null, { disposeWhenNodeIsRemoved: element });
            return { 'controlsDescendantBindings': true };
        }
    };
    ko.expressionRewriting.bindingRewriteValidators[bindingKey] = false; // Can't rewrite control flow bindings
    ko.virtualElements.allowedBindings[bindingKey] = true;
}

// Construct the actual binding handlers
makeWithIfBinding('if');
makeWithIfBinding('ifnot', false /* isWith */, true /* isNot */);
makeWithIfBinding('with', true /* isWith */, false /* isNot */,
    function(bindingContext, dataValue) {
        return bindingContext['createChildContext'](dataValue);
    }
);
var captionPlaceholder = {};
ko.bindingHandlers['options'] = {
    'init': function(element) {
        if (ko.utils.tagNameLower(element) !== "select")
            throw new Error("options binding applies only to SELECT elements");

        // Remove all existing <option>s.
        while (element.length > 0) {
            element.remove(0);
        }

        // Ensures that the binding processor doesn't try to bind the options
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor, allBindings) {
        function selectedOptions() {
            return ko.utils.arrayFilter(element.options, function (node) { return node.selected; });
        }

        var selectWasPreviouslyEmpty = element.length == 0,
            multiple = element.multiple,
            previousScrollTop = (!selectWasPreviouslyEmpty && multiple) ? element.scrollTop : null,
            unwrappedArray = ko.utils.unwrapObservable(valueAccessor()),
            valueAllowUnset = allBindings.get('valueAllowUnset') && allBindings['has']('value'),
            includeDestroyed = allBindings.get('optionsIncludeDestroyed'),
            arrayToDomNodeChildrenOptions = {},
            captionValue,
            filteredArray,
            previousSelectedValues = [];

        if (!valueAllowUnset) {
            if (multiple) {
                previousSelectedValues = ko.utils.arrayMap(selectedOptions(), ko.selectExtensions.readValue);
            } else if (element.selectedIndex >= 0) {
                previousSelectedValues.push(ko.selectExtensions.readValue(element.options[element.selectedIndex]));
            }
        }

        if (unwrappedArray) {
            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
                unwrappedArray = [unwrappedArray];

            // Filter out any entries marked as destroyed
            filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
                return includeDestroyed || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
            });

            // If caption is included, add it to the array
            if (allBindings['has']('optionsCaption')) {
                captionValue = ko.utils.unwrapObservable(allBindings.get('optionsCaption'));
                // If caption value is null or undefined, don't show a caption
                if (captionValue !== null && captionValue !== undefined) {
                    filteredArray.unshift(captionPlaceholder);
                }
            }
        } else {
            // If a falsy value is provided (e.g. null), we'll simply empty the select element
        }

        function applyToObject(object, predicate, defaultValue) {
            var predicateType = typeof predicate;
            if (predicateType == "function")    // Given a function; run it against the data value
                return predicate(object);
            else if (predicateType == "string") // Given a string; treat it as a property name on the data value
                return object[predicate];
            else                                // Given no optionsText arg; use the data value itself
                return defaultValue;
        }

        // The following functions can run at two different times:
        // The first is when the whole array is being updated directly from this binding handler.
        // The second is when an observable value for a specific array entry is updated.
        // oldOptions will be empty in the first case, but will be filled with the previously generated option in the second.
        var itemUpdate = false;
        function optionForArrayItem(arrayEntry, index, oldOptions) {
            if (oldOptions.length) {
                previousSelectedValues = !valueAllowUnset && oldOptions[0].selected ? [ ko.selectExtensions.readValue(oldOptions[0]) ] : [];
                itemUpdate = true;
            }
            var option = element.ownerDocument.createElement("option");
            if (arrayEntry === captionPlaceholder) {
                ko.utils.setTextContent(option, allBindings.get('optionsCaption'));
                ko.selectExtensions.writeValue(option, undefined);
            } else {
                // Apply a value to the option element
                var optionValue = applyToObject(arrayEntry, allBindings.get('optionsValue'), arrayEntry);
                ko.selectExtensions.writeValue(option, ko.utils.unwrapObservable(optionValue));

                // Apply some text to the option element
                var optionText = applyToObject(arrayEntry, allBindings.get('optionsText'), optionValue);
                ko.utils.setTextContent(option, optionText);
            }
            return [option];
        }

        // By using a beforeRemove callback, we delay the removal until after new items are added. This fixes a selection
        // problem in IE<=8 and Firefox. See https://github.com/knockout/knockout/issues/1208
        arrayToDomNodeChildrenOptions['beforeRemove'] =
            function (option) {
                element.removeChild(option);
            };

        function setSelectionCallback(arrayEntry, newOptions) {
            if (itemUpdate && valueAllowUnset) {
                // The model value is authoritative, so make sure its value is the one selected
                // There is no need to use dependencyDetection.ignore since setDomNodeChildrenFromArrayMapping does so already.
                ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
            } else if (previousSelectedValues.length) {
                // IE6 doesn't like us to assign selection to OPTION nodes before they're added to the document.
                // That's why we first added them without selection. Now it's time to set the selection.
                var isSelected = ko.utils.arrayIndexOf(previousSelectedValues, ko.selectExtensions.readValue(newOptions[0])) >= 0;
                ko.utils.setOptionNodeSelectionState(newOptions[0], isSelected);

                // If this option was changed from being selected during a single-item update, notify the change
                if (itemUpdate && !isSelected) {
                    ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
                }
            }
        }

        var callback = setSelectionCallback;
        if (allBindings['has']('optionsAfterRender') && typeof allBindings.get('optionsAfterRender') == "function") {
            callback = function(arrayEntry, newOptions) {
                setSelectionCallback(arrayEntry, newOptions);
                ko.dependencyDetection.ignore(allBindings.get('optionsAfterRender'), null, [newOptions[0], arrayEntry !== captionPlaceholder ? arrayEntry : undefined]);
            }
        }

        ko.utils.setDomNodeChildrenFromArrayMapping(element, filteredArray, optionForArrayItem, arrayToDomNodeChildrenOptions, callback);

        ko.dependencyDetection.ignore(function () {
            if (valueAllowUnset) {
                // The model value is authoritative, so make sure its value is the one selected
                ko.selectExtensions.writeValue(element, ko.utils.unwrapObservable(allBindings.get('value')), true /* allowUnset */);
            } else {
                // Determine if the selection has changed as a result of updating the options list
                var selectionChanged;
                if (multiple) {
                    // For a multiple-select box, compare the new selection count to the previous one
                    // But if nothing was selected before, the selection can't have changed
                    selectionChanged = previousSelectedValues.length && selectedOptions().length < previousSelectedValues.length;
                } else {
                    // For a single-select box, compare the current value to the previous value
                    // But if nothing was selected before or nothing is selected now, just look for a change in selection
                    selectionChanged = (previousSelectedValues.length && element.selectedIndex >= 0)
                        ? (ko.selectExtensions.readValue(element.options[element.selectedIndex]) !== previousSelectedValues[0])
                        : (previousSelectedValues.length || element.selectedIndex >= 0);
                }

                // Ensure consistency between model value and selected option.
                // If the dropdown was changed so that selection is no longer the same,
                // notify the value or selectedOptions binding.
                if (selectionChanged) {
                    ko.utils.triggerEvent(element, "change");
                }
            }
        });

        // Workaround for IE bug
        ko.utils.ensureSelectElementIsRenderedCorrectly(element);

        if (previousScrollTop && Math.abs(previousScrollTop - element.scrollTop) > 20)
            element.scrollTop = previousScrollTop;
    }
};
ko.bindingHandlers['options'].optionValueDomDataKey = ko.utils.domData.nextKey();
ko.bindingHandlers['selectedOptions'] = {
    'after': ['options', 'foreach'],
    'init': function (element, valueAccessor, allBindings) {
        ko.utils.registerEventHandler(element, "change", function () {
            var value = valueAccessor(), valueToWrite = [];
            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
                if (node.selected)
                    valueToWrite.push(ko.selectExtensions.readValue(node));
            });
            ko.expressionRewriting.writeValueToProperty(value, allBindings, 'selectedOptions', valueToWrite);
        });
    },
    'update': function (element, valueAccessor) {
        if (ko.utils.tagNameLower(element) != "select")
            throw new Error("values binding applies only to SELECT elements");

        var newValue = ko.utils.unwrapObservable(valueAccessor()),
            previousScrollTop = element.scrollTop;

        if (newValue && typeof newValue.length == "number") {
            ko.utils.arrayForEach(element.getElementsByTagName("option"), function(node) {
                var isSelected = ko.utils.arrayIndexOf(newValue, ko.selectExtensions.readValue(node)) >= 0;
                if (node.selected != isSelected) {      // This check prevents flashing of the select element in IE
                    ko.utils.setOptionNodeSelectionState(node, isSelected);
                }
            });
        }

        element.scrollTop = previousScrollTop;
    }
};
ko.expressionRewriting.twoWayBindings['selectedOptions'] = true;
ko.bindingHandlers['style'] = {
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor() || {});
        ko.utils.objectForEach(value, function(styleName, styleValue) {
            styleValue = ko.utils.unwrapObservable(styleValue);

            if (styleValue === null || styleValue === undefined || styleValue === false) {
                // Empty string removes the value, whereas null/undefined have no effect
                styleValue = "";
            }

            element.style[styleName] = styleValue;
        });
    }
};
ko.bindingHandlers['submit'] = {
    'init': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        if (typeof valueAccessor() != "function")
            throw new Error("The value for a submit binding must be a function");
        ko.utils.registerEventHandler(element, "submit", function (event) {
            var handlerReturnValue;
            var value = valueAccessor();
            try { handlerReturnValue = value.call(bindingContext['$data'], element); }
            finally {
                if (handlerReturnValue !== true) { // Normally we want to prevent default action. Developer can override this be explicitly returning true.
                    if (event.preventDefault)
                        event.preventDefault();
                    else
                        event.returnValue = false;
                }
            }
        });
    }
};
ko.bindingHandlers['text'] = {
    'init': function() {
        // Prevent binding on the dynamically-injected text node (as developers are unlikely to expect that, and it has security implications).
        // It should also make things faster, as we no longer have to consider whether the text node might be bindable.
        return { 'controlsDescendantBindings': true };
    },
    'update': function (element, valueAccessor) {
        ko.utils.setTextContent(element, valueAccessor());
    }
};
ko.virtualElements.allowedBindings['text'] = true;
(function () {

if (window && window.navigator) {
    var parseVersion = function (matches) {
        if (matches) {
            return parseFloat(matches[1]);
        }
    };

    // Detect various browser versions because some old versions don't fully support the 'input' event
    var operaVersion = window.opera && window.opera.version && parseInt(window.opera.version()),
        userAgent = window.navigator.userAgent,
        safariVersion = parseVersion(userAgent.match(/^(?:(?!chrome).)*version\/([^ ]*) safari/i)),
        firefoxVersion = parseVersion(userAgent.match(/Firefox\/([^ ]*)/));
}

// IE 8 and 9 have bugs that prevent the normal events from firing when the value changes.
// But it does fire the 'selectionchange' event on many of those, presumably because the
// cursor is moving and that counts as the selection changing. The 'selectionchange' event is
// fired at the document level only and doesn't directly indicate which element changed. We
// set up just one event handler for the document and use 'activeElement' to determine which
// element was changed.
if (ko.utils.ieVersion < 10) {
    var selectionChangeRegisteredName = ko.utils.domData.nextKey(),
        selectionChangeHandlerName = ko.utils.domData.nextKey();
    var selectionChangeHandler = function(event) {
        var target = this.activeElement,
            handler = target && ko.utils.domData.get(target, selectionChangeHandlerName);
        if (handler) {
            handler(event);
        }
    };
    var registerForSelectionChangeEvent = function (element, handler) {
        var ownerDoc = element.ownerDocument;
        if (!ko.utils.domData.get(ownerDoc, selectionChangeRegisteredName)) {
            ko.utils.domData.set(ownerDoc, selectionChangeRegisteredName, true);
            ko.utils.registerEventHandler(ownerDoc, 'selectionchange', selectionChangeHandler);
        }
        ko.utils.domData.set(element, selectionChangeHandlerName, handler);
    };
}

ko.bindingHandlers['textInput'] = {
    'init': function (element, valueAccessor, allBindings) {

        var previousElementValue = element.value,
            timeoutHandle,
            elementValueBeforeEvent;

        var updateModel = function (event) {
            clearTimeout(timeoutHandle);
            elementValueBeforeEvent = timeoutHandle = undefined;

            var elementValue = element.value;
            if (previousElementValue !== elementValue) {
                // Provide a way for tests to know exactly which event was processed
                if (DEBUG && event) element['_ko_textInputProcessedEvent'] = event.type;
                previousElementValue = elementValue;
                ko.expressionRewriting.writeValueToProperty(valueAccessor(), allBindings, 'textInput', elementValue);
            }
        };

        var deferUpdateModel = function (event) {
            if (!timeoutHandle) {
                // The elementValueBeforeEvent variable is set *only* during the brief gap between an
                // event firing and the updateModel function running. This allows us to ignore model
                // updates that are from the previous state of the element, usually due to techniques
                // such as rateLimit. Such updates, if not ignored, can cause keystrokes to be lost.
                elementValueBeforeEvent = element.value;
                var handler = DEBUG ? updateModel.bind(element, {type: event.type}) : updateModel;
                timeoutHandle = ko.utils.setTimeout(handler, 4);
            }
        };

        // IE9 will mess up the DOM if you handle events synchronously which results in DOM changes (such as other bindings);
        // so we'll make sure all updates are asynchronous
        var ieUpdateModel = ko.utils.ieVersion == 9 ? deferUpdateModel : updateModel;

        var updateView = function () {
            var modelValue = ko.utils.unwrapObservable(valueAccessor());

            if (modelValue === null || modelValue === undefined) {
                modelValue = '';
            }

            if (elementValueBeforeEvent !== undefined && modelValue === elementValueBeforeEvent) {
                ko.utils.setTimeout(updateView, 4);
                return;
            }

            // Update the element only if the element and model are different. On some browsers, updating the value
            // will move the cursor to the end of the input, which would be bad while the user is typing.
            if (element.value !== modelValue) {
                previousElementValue = modelValue;  // Make sure we ignore events (propertychange) that result from updating the value
                element.value = modelValue;
            }
        };

        var onEvent = function (event, handler) {
            ko.utils.registerEventHandler(element, event, handler);
        };

        if (DEBUG && ko.bindingHandlers['textInput']['_forceUpdateOn']) {
            // Provide a way for tests to specify exactly which events are bound
            ko.utils.arrayForEach(ko.bindingHandlers['textInput']['_forceUpdateOn'], function(eventName) {
                if (eventName.slice(0,5) == 'after') {
                    onEvent(eventName.slice(5), deferUpdateModel);
                } else {
                    onEvent(eventName, updateModel);
                }
            });
        } else {
            if (ko.utils.ieVersion < 10) {
                // Internet Explorer <= 8 doesn't support the 'input' event, but does include 'propertychange' that fires whenever
                // any property of an element changes. Unlike 'input', it also fires if a property is changed from JavaScript code,
                // but that's an acceptable compromise for this binding. IE 9 does support 'input', but since it doesn't fire it
                // when using autocomplete, we'll use 'propertychange' for it also.
                onEvent('propertychange', function(event) {
                    if (event.propertyName === 'value') {
                        ieUpdateModel(event);
                    }
                });

                if (ko.utils.ieVersion == 8) {
                    // IE 8 has a bug where it fails to fire 'propertychange' on the first update following a value change from
                    // JavaScript code. It also doesn't fire if you clear the entire value. To fix this, we bind to the following
                    // events too.
                    onEvent('keyup', updateModel);      // A single keystoke
                    onEvent('keydown', updateModel);    // The first character when a key is held down
                }
                if (ko.utils.ieVersion >= 8) {
                    // Internet Explorer 9 doesn't fire the 'input' event when deleting text, including using
                    // the backspace, delete, or ctrl-x keys, clicking the 'x' to clear the input, dragging text
                    // out of the field, and cutting or deleting text using the context menu. 'selectionchange'
                    // can detect all of those except dragging text out of the field, for which we use 'dragend'.
                    // These are also needed in IE8 because of the bug described above.
                    registerForSelectionChangeEvent(element, ieUpdateModel);  // 'selectionchange' covers cut, paste, drop, delete, etc.
                    onEvent('dragend', deferUpdateModel);
                }
            } else {
                // All other supported browsers support the 'input' event, which fires whenever the content of the element is changed
                // through the user interface.
                onEvent('input', updateModel);

                if (safariVersion < 5 && ko.utils.tagNameLower(element) === "textarea") {
                    // Safari <5 doesn't fire the 'input' event for <textarea> elements (it does fire 'textInput'
                    // but only when typing). So we'll just catch as much as we can with keydown, cut, and paste.
                    onEvent('keydown', deferUpdateModel);
                    onEvent('paste', deferUpdateModel);
                    onEvent('cut', deferUpdateModel);
                } else if (operaVersion < 11) {
                    // Opera 10 doesn't always fire the 'input' event for cut, paste, undo & drop operations.
                    // We can try to catch some of those using 'keydown'.
                    onEvent('keydown', deferUpdateModel);
                } else if (firefoxVersion < 4.0) {
                    // Firefox <= 3.6 doesn't fire the 'input' event when text is filled in through autocomplete
                    onEvent('DOMAutoComplete', updateModel);

                    // Firefox <=3.5 doesn't fire the 'input' event when text is dropped into the input.
                    onEvent('dragdrop', updateModel);       // <3.5
                    onEvent('drop', updateModel);           // 3.5
                }
            }
        }

        // Bind to the change event so that we can catch programmatic updates of the value that fire this event.
        onEvent('change', updateModel);

        ko.computed(updateView, null, { disposeWhenNodeIsRemoved: element });
    }
};
ko.expressionRewriting.twoWayBindings['textInput'] = true;

// textinput is an alias for textInput
ko.bindingHandlers['textinput'] = {
    // preprocess is the only way to set up a full alias
    'preprocess': function (value, name, addBinding) {
        addBinding('textInput', value);
    }
};

})();ko.bindingHandlers['uniqueName'] = {
    'init': function (element, valueAccessor) {
        if (valueAccessor()) {
            var name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex);
            ko.utils.setElementName(element, name);
        }
    }
};
ko.bindingHandlers['uniqueName'].currentIndex = 0;
ko.bindingHandlers['value'] = {
    'after': ['options', 'foreach'],
    'init': function (element, valueAccessor, allBindings) {
        // If the value binding is placed on a radio/checkbox, then just pass through to checkedValue and quit
        if (element.tagName.toLowerCase() == "input" && (element.type == "checkbox" || element.type == "radio")) {
            ko.applyBindingAccessorsToNode(element, { 'checkedValue': valueAccessor });
            return;
        }

        // Always catch "change" event; possibly other events too if asked
        var eventsToCatch = ["change"];
        var requestedEventsToCatch = allBindings.get("valueUpdate");
        var propertyChangedFired = false;
        var elementValueBeforeEvent = null;

        if (requestedEventsToCatch) {
            if (typeof requestedEventsToCatch == "string") // Allow both individual event names, and arrays of event names
                requestedEventsToCatch = [requestedEventsToCatch];
            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
        }

        var valueUpdateHandler = function() {
            elementValueBeforeEvent = null;
            propertyChangedFired = false;
            var modelValue = valueAccessor();
            var elementValue = ko.selectExtensions.readValue(element);
            ko.expressionRewriting.writeValueToProperty(modelValue, allBindings, 'value', elementValue);
        }

        // Workaround for https://github.com/SteveSanderson/knockout/issues/122
        // IE doesn't fire "change" events on textboxes if the user selects a value from its autocomplete list
        var ieAutoCompleteHackNeeded = ko.utils.ieVersion && element.tagName.toLowerCase() == "input" && element.type == "text"
                                       && element.autocomplete != "off" && (!element.form || element.form.autocomplete != "off");
        if (ieAutoCompleteHackNeeded && ko.utils.arrayIndexOf(eventsToCatch, "propertychange") == -1) {
            ko.utils.registerEventHandler(element, "propertychange", function () { propertyChangedFired = true });
            ko.utils.registerEventHandler(element, "focus", function () { propertyChangedFired = false });
            ko.utils.registerEventHandler(element, "blur", function() {
                if (propertyChangedFired) {
                    valueUpdateHandler();
                }
            });
        }

        ko.utils.arrayForEach(eventsToCatch, function(eventName) {
            // The syntax "after<eventname>" means "run the handler asynchronously after the event"
            // This is useful, for example, to catch "keydown" events after the browser has updated the control
            // (otherwise, ko.selectExtensions.readValue(this) will receive the control's value *before* the key event)
            var handler = valueUpdateHandler;
            if (ko.utils.stringStartsWith(eventName, "after")) {
                handler = function() {
                    // The elementValueBeforeEvent variable is non-null *only* during the brief gap between
                    // a keyX event firing and the valueUpdateHandler running, which is scheduled to happen
                    // at the earliest asynchronous opportunity. We store this temporary information so that
                    // if, between keyX and valueUpdateHandler, the underlying model value changes separately,
                    // we can overwrite that model value change with the value the user just typed. Otherwise,
                    // techniques like rateLimit can trigger model changes at critical moments that will
                    // override the user's inputs, causing keystrokes to be lost.
                    elementValueBeforeEvent = ko.selectExtensions.readValue(element);
                    ko.utils.setTimeout(valueUpdateHandler, 0);
                };
                eventName = eventName.substring("after".length);
            }
            ko.utils.registerEventHandler(element, eventName, handler);
        });

        var updateFromModel = function () {
            var newValue = ko.utils.unwrapObservable(valueAccessor());
            var elementValue = ko.selectExtensions.readValue(element);

            if (elementValueBeforeEvent !== null && newValue === elementValueBeforeEvent) {
                ko.utils.setTimeout(updateFromModel, 0);
                return;
            }

            var valueHasChanged = (newValue !== elementValue);

            if (valueHasChanged) {
                if (ko.utils.tagNameLower(element) === "select") {
                    var allowUnset = allBindings.get('valueAllowUnset');
                    var applyValueAction = function () {
                        ko.selectExtensions.writeValue(element, newValue, allowUnset);
                    };
                    applyValueAction();

                    if (!allowUnset && newValue !== ko.selectExtensions.readValue(element)) {
                        // If you try to set a model value that can't be represented in an already-populated dropdown, reject that change,
                        // because you're not allowed to have a model value that disagrees with a visible UI selection.
                        ko.dependencyDetection.ignore(ko.utils.triggerEvent, null, [element, "change"]);
                    } else {
                        // Workaround for IE6 bug: It won't reliably apply values to SELECT nodes during the same execution thread
                        // right after you've changed the set of OPTION nodes on it. So for that node type, we'll schedule a second thread
                        // to apply the value as well.
                        ko.utils.setTimeout(applyValueAction, 0);
                    }
                } else {
                    ko.selectExtensions.writeValue(element, newValue);
                }
            }
        };

        ko.computed(updateFromModel, null, { disposeWhenNodeIsRemoved: element });
    },
    'update': function() {} // Keep for backwards compatibility with code that may have wrapped value binding
};
ko.expressionRewriting.twoWayBindings['value'] = true;
ko.bindingHandlers['visible'] = {
    'update': function (element, valueAccessor) {
        var value = ko.utils.unwrapObservable(valueAccessor());
        var isCurrentlyVisible = !(element.style.display == "none");
        if (value && !isCurrentlyVisible)
            element.style.display = "";
        else if ((!value) && isCurrentlyVisible)
            element.style.display = "none";
    }
};
// 'click' is just a shorthand for the usual full-length event:{click:handler}
makeEventHandlerShortcut('click');
// If you want to make a custom template engine,
//
// [1] Inherit from this class (like ko.nativeTemplateEngine does)
// [2] Override 'renderTemplateSource', supplying a function with this signature:
//
//        function (templateSource, bindingContext, options) {
//            // - templateSource.text() is the text of the template you should render
//            // - bindingContext.$data is the data you should pass into the template
//            //   - you might also want to make bindingContext.$parent, bindingContext.$parents,
//            //     and bindingContext.$root available in the template too
//            // - options gives you access to any other properties set on "data-bind: { template: options }"
//            // - templateDocument is the document object of the template
//            //
//            // Return value: an array of DOM nodes
//        }
//
// [3] Override 'createJavaScriptEvaluatorBlock', supplying a function with this signature:
//
//        function (script) {
//            // Return value: Whatever syntax means "Evaluate the JavaScript statement 'script' and output the result"
//            //               For example, the jquery.tmpl template engine converts 'someScript' to '${ someScript }'
//        }
//
//     This is only necessary if you want to allow data-bind attributes to reference arbitrary template variables.
//     If you don't want to allow that, you can set the property 'allowTemplateRewriting' to false (like ko.nativeTemplateEngine does)
//     and then you don't need to override 'createJavaScriptEvaluatorBlock'.

ko.templateEngine = function () { };

ko.templateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
    throw new Error("Override renderTemplateSource");
};

ko.templateEngine.prototype['createJavaScriptEvaluatorBlock'] = function (script) {
    throw new Error("Override createJavaScriptEvaluatorBlock");
};

ko.templateEngine.prototype['makeTemplateSource'] = function(template, templateDocument) {
    // Named template
    if (typeof template == "string") {
        templateDocument = templateDocument || document;
        var elem = templateDocument.getElementById(template);
        if (!elem)
            throw new Error("Cannot find template with ID " + template);
        return new ko.templateSources.domElement(elem);
    } else if ((template.nodeType == 1) || (template.nodeType == 8)) {
        // Anonymous template
        return new ko.templateSources.anonymousTemplate(template);
    } else
        throw new Error("Unknown template type: " + template);
};

ko.templateEngine.prototype['renderTemplate'] = function (template, bindingContext, options, templateDocument) {
    var templateSource = this['makeTemplateSource'](template, templateDocument);
    return this['renderTemplateSource'](templateSource, bindingContext, options, templateDocument);
};

ko.templateEngine.prototype['isTemplateRewritten'] = function (template, templateDocument) {
    // Skip rewriting if requested
    if (this['allowTemplateRewriting'] === false)
        return true;
    return this['makeTemplateSource'](template, templateDocument)['data']("isRewritten");
};

ko.templateEngine.prototype['rewriteTemplate'] = function (template, rewriterCallback, templateDocument) {
    var templateSource = this['makeTemplateSource'](template, templateDocument);
    var rewritten = rewriterCallback(templateSource['text']());
    templateSource['text'](rewritten);
    templateSource['data']("isRewritten", true);
};

ko.exportSymbol('templateEngine', ko.templateEngine);

ko.templateRewriting = (function () {
    var memoizeDataBindingAttributeSyntaxRegex = /(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi;
    var memoizeVirtualContainerBindingSyntaxRegex = /<!--\s*ko\b\s*([\s\S]*?)\s*-->/g;

    function validateDataBindValuesForRewriting(keyValueArray) {
        var allValidators = ko.expressionRewriting.bindingRewriteValidators;
        for (var i = 0; i < keyValueArray.length; i++) {
            var key = keyValueArray[i]['key'];
            if (allValidators.hasOwnProperty(key)) {
                var validator = allValidators[key];

                if (typeof validator === "function") {
                    var possibleErrorMessage = validator(keyValueArray[i]['value']);
                    if (possibleErrorMessage)
                        throw new Error(possibleErrorMessage);
                } else if (!validator) {
                    throw new Error("This template engine does not support the '" + key + "' binding within its templates");
                }
            }
        }
    }

    function constructMemoizedTagReplacement(dataBindAttributeValue, tagToRetain, nodeName, templateEngine) {
        var dataBindKeyValueArray = ko.expressionRewriting.parseObjectLiteral(dataBindAttributeValue);
        validateDataBindValuesForRewriting(dataBindKeyValueArray);
        var rewrittenDataBindAttributeValue = ko.expressionRewriting.preProcessBindings(dataBindKeyValueArray, {'valueAccessors':true});

        // For no obvious reason, Opera fails to evaluate rewrittenDataBindAttributeValue unless it's wrapped in an additional
        // anonymous function, even though Opera's built-in debugger can evaluate it anyway. No other browser requires this
        // extra indirection.
        var applyBindingsToNextSiblingScript =
            "ko.__tr_ambtns(function($context,$element){return(function(){return{ " + rewrittenDataBindAttributeValue + " } })()},'" + nodeName.toLowerCase() + "')";
        return templateEngine['createJavaScriptEvaluatorBlock'](applyBindingsToNextSiblingScript) + tagToRetain;
    }

    return {
        ensureTemplateIsRewritten: function (template, templateEngine, templateDocument) {
            if (!templateEngine['isTemplateRewritten'](template, templateDocument))
                templateEngine['rewriteTemplate'](template, function (htmlString) {
                    return ko.templateRewriting.memoizeBindingAttributeSyntax(htmlString, templateEngine);
                }, templateDocument);
        },

        memoizeBindingAttributeSyntax: function (htmlString, templateEngine) {
            return htmlString.replace(memoizeDataBindingAttributeSyntaxRegex, function () {
                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[4], /* tagToRetain: */ arguments[1], /* nodeName: */ arguments[2], templateEngine);
            }).replace(memoizeVirtualContainerBindingSyntaxRegex, function() {
                return constructMemoizedTagReplacement(/* dataBindAttributeValue: */ arguments[1], /* tagToRetain: */ "<!-- ko -->", /* nodeName: */ "#comment", templateEngine);
            });
        },

        applyMemoizedBindingsToNextSibling: function (bindings, nodeName) {
            return ko.memoization.memoize(function (domNode, bindingContext) {
                var nodeToBind = domNode.nextSibling;
                if (nodeToBind && nodeToBind.nodeName.toLowerCase() === nodeName) {
                    ko.applyBindingAccessorsToNode(nodeToBind, bindings, bindingContext);
                }
            });
        }
    }
})();


// Exported only because it has to be referenced by string lookup from within rewritten template
ko.exportSymbol('__tr_ambtns', ko.templateRewriting.applyMemoizedBindingsToNextSibling);
(function() {
    // A template source represents a read/write way of accessing a template. This is to eliminate the need for template loading/saving
    // logic to be duplicated in every template engine (and means they can all work with anonymous templates, etc.)
    //
    // Two are provided by default:
    //  1. ko.templateSources.domElement       - reads/writes the text content of an arbitrary DOM element
    //  2. ko.templateSources.anonymousElement - uses ko.utils.domData to read/write text *associated* with the DOM element, but
    //                                           without reading/writing the actual element text content, since it will be overwritten
    //                                           with the rendered template output.
    // You can implement your own template source if you want to fetch/store templates somewhere other than in DOM elements.
    // Template sources need to have the following functions:
    //   text() 			- returns the template text from your storage location
    //   text(value)		- writes the supplied template text to your storage location
    //   data(key)			- reads values stored using data(key, value) - see below
    //   data(key, value)	- associates "value" with this template and the key "key". Is used to store information like "isRewritten".
    //
    // Optionally, template sources can also have the following functions:
    //   nodes()            - returns a DOM element containing the nodes of this template, where available
    //   nodes(value)       - writes the given DOM element to your storage location
    // If a DOM element is available for a given template source, template engines are encouraged to use it in preference over text()
    // for improved speed. However, all templateSources must supply text() even if they don't supply nodes().
    //
    // Once you've implemented a templateSource, make your template engine use it by subclassing whatever template engine you were
    // using and overriding "makeTemplateSource" to return an instance of your custom template source.

    ko.templateSources = {};

    // ---- ko.templateSources.domElement -----

    // template types
    var templateScript = 1,
        templateTextArea = 2,
        templateTemplate = 3,
        templateElement = 4;

    ko.templateSources.domElement = function(element) {
        this.domElement = element;

        if (element) {
            var tagNameLower = ko.utils.tagNameLower(element);
            this.templateType =
                tagNameLower === "script" ? templateScript :
                tagNameLower === "textarea" ? templateTextArea :
                    // For browsers with proper <template> element support, where the .content property gives a document fragment
                tagNameLower == "template" && element.content && element.content.nodeType === 11 ? templateTemplate :
                templateElement;
        }
    }

    ko.templateSources.domElement.prototype['text'] = function(/* valueToWrite */) {
        var elemContentsProperty = this.templateType === templateScript ? "text"
                                 : this.templateType === templateTextArea ? "value"
                                 : "innerHTML";

        if (arguments.length == 0) {
            return this.domElement[elemContentsProperty];
        } else {
            var valueToWrite = arguments[0];
            if (elemContentsProperty === "innerHTML")
                ko.utils.setHtml(this.domElement, valueToWrite);
            else
                this.domElement[elemContentsProperty] = valueToWrite;
        }
    };

    var dataDomDataPrefix = ko.utils.domData.nextKey() + "_";
    ko.templateSources.domElement.prototype['data'] = function(key /*, valueToWrite */) {
        if (arguments.length === 1) {
            return ko.utils.domData.get(this.domElement, dataDomDataPrefix + key);
        } else {
            ko.utils.domData.set(this.domElement, dataDomDataPrefix + key, arguments[1]);
        }
    };

    var templatesDomDataKey = ko.utils.domData.nextKey();
    function getTemplateDomData(element) {
        return ko.utils.domData.get(element, templatesDomDataKey) || {};
    }
    function setTemplateDomData(element, data) {
        ko.utils.domData.set(element, templatesDomDataKey, data);
    }

    ko.templateSources.domElement.prototype['nodes'] = function(/* valueToWrite */) {
        var element = this.domElement;
        if (arguments.length == 0) {
            var templateData = getTemplateDomData(element),
                containerData = templateData.containerData;
            return containerData || (
                this.templateType === templateTemplate ? element.content :
                this.templateType === templateElement ? element :
                undefined);
        } else {
            var valueToWrite = arguments[0];
            setTemplateDomData(element, {containerData: valueToWrite});
        }
    };

    // ---- ko.templateSources.anonymousTemplate -----
    // Anonymous templates are normally saved/retrieved as DOM nodes through "nodes".
    // For compatibility, you can also read "text"; it will be serialized from the nodes on demand.
    // Writing to "text" is still supported, but then the template data will not be available as DOM nodes.

    ko.templateSources.anonymousTemplate = function(element) {
        this.domElement = element;
    }
    ko.templateSources.anonymousTemplate.prototype = new ko.templateSources.domElement();
    ko.templateSources.anonymousTemplate.prototype.constructor = ko.templateSources.anonymousTemplate;
    ko.templateSources.anonymousTemplate.prototype['text'] = function(/* valueToWrite */) {
        if (arguments.length == 0) {
            var templateData = getTemplateDomData(this.domElement);
            if (templateData.textData === undefined && templateData.containerData)
                templateData.textData = templateData.containerData.innerHTML;
            return templateData.textData;
        } else {
            var valueToWrite = arguments[0];
            setTemplateDomData(this.domElement, {textData: valueToWrite});
        }
    };

    ko.exportSymbol('templateSources', ko.templateSources);
    ko.exportSymbol('templateSources.domElement', ko.templateSources.domElement);
    ko.exportSymbol('templateSources.anonymousTemplate', ko.templateSources.anonymousTemplate);
})();
(function () {
    var _templateEngine;
    ko.setTemplateEngine = function (templateEngine) {
        if ((templateEngine != undefined) && !(templateEngine instanceof ko.templateEngine))
            throw new Error("templateEngine must inherit from ko.templateEngine");
        _templateEngine = templateEngine;
    }

    function invokeForEachNodeInContinuousRange(firstNode, lastNode, action) {
        var node, nextInQueue = firstNode, firstOutOfRangeNode = ko.virtualElements.nextSibling(lastNode);
        while (nextInQueue && ((node = nextInQueue) !== firstOutOfRangeNode)) {
            nextInQueue = ko.virtualElements.nextSibling(node);
            action(node, nextInQueue);
        }
    }

    function activateBindingsOnContinuousNodeArray(continuousNodeArray, bindingContext) {
        // To be used on any nodes that have been rendered by a template and have been inserted into some parent element
        // Walks through continuousNodeArray (which *must* be continuous, i.e., an uninterrupted sequence of sibling nodes, because
        // the algorithm for walking them relies on this), and for each top-level item in the virtual-element sense,
        // (1) Does a regular "applyBindings" to associate bindingContext with this node and to activate any non-memoized bindings
        // (2) Unmemoizes any memos in the DOM subtree (e.g., to activate bindings that had been memoized during template rewriting)

        if (continuousNodeArray.length) {
            var firstNode = continuousNodeArray[0],
                lastNode = continuousNodeArray[continuousNodeArray.length - 1],
                parentNode = firstNode.parentNode,
                provider = ko.bindingProvider['instance'],
                preprocessNode = provider['preprocessNode'];

            if (preprocessNode) {
                invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node, nextNodeInRange) {
                    var nodePreviousSibling = node.previousSibling;
                    var newNodes = preprocessNode.call(provider, node);
                    if (newNodes) {
                        if (node === firstNode)
                            firstNode = newNodes[0] || nextNodeInRange;
                        if (node === lastNode)
                            lastNode = newNodes[newNodes.length - 1] || nodePreviousSibling;
                    }
                });

                // Because preprocessNode can change the nodes, including the first and last nodes, update continuousNodeArray to match.
                // We need the full set, including inner nodes, because the unmemoize step might remove the first node (and so the real
                // first node needs to be in the array).
                continuousNodeArray.length = 0;
                if (!firstNode) { // preprocessNode might have removed all the nodes, in which case there's nothing left to do
                    return;
                }
                if (firstNode === lastNode) {
                    continuousNodeArray.push(firstNode);
                } else {
                    continuousNodeArray.push(firstNode, lastNode);
                    ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
                }
            }

            // Need to applyBindings *before* unmemoziation, because unmemoization might introduce extra nodes (that we don't want to re-bind)
            // whereas a regular applyBindings won't introduce new memoized nodes
            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
                if (node.nodeType === 1 || node.nodeType === 8)
                    ko.applyBindings(bindingContext, node);
            });
            invokeForEachNodeInContinuousRange(firstNode, lastNode, function(node) {
                if (node.nodeType === 1 || node.nodeType === 8)
                    ko.memoization.unmemoizeDomNodeAndDescendants(node, [bindingContext]);
            });

            // Make sure any changes done by applyBindings or unmemoize are reflected in the array
            ko.utils.fixUpContinuousNodeArray(continuousNodeArray, parentNode);
        }
    }

    function getFirstNodeFromPossibleArray(nodeOrNodeArray) {
        return nodeOrNodeArray.nodeType ? nodeOrNodeArray
                                        : nodeOrNodeArray.length > 0 ? nodeOrNodeArray[0]
                                        : null;
    }

    function executeTemplate(targetNodeOrNodeArray, renderMode, template, bindingContext, options) {
        options = options || {};
        var firstTargetNode = targetNodeOrNodeArray && getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
        var templateDocument = (firstTargetNode || template || {}).ownerDocument;
        var templateEngineToUse = (options['templateEngine'] || _templateEngine);
        ko.templateRewriting.ensureTemplateIsRewritten(template, templateEngineToUse, templateDocument);
        var renderedNodesArray = templateEngineToUse['renderTemplate'](template, bindingContext, options, templateDocument);

        // Loosely check result is an array of DOM nodes
        if ((typeof renderedNodesArray.length != "number") || (renderedNodesArray.length > 0 && typeof renderedNodesArray[0].nodeType != "number"))
            throw new Error("Template engine must return an array of DOM nodes");

        var haveAddedNodesToParent = false;
        switch (renderMode) {
            case "replaceChildren":
                ko.virtualElements.setDomNodeChildren(targetNodeOrNodeArray, renderedNodesArray);
                haveAddedNodesToParent = true;
                break;
            case "replaceNode":
                ko.utils.replaceDomNodes(targetNodeOrNodeArray, renderedNodesArray);
                haveAddedNodesToParent = true;
                break;
            case "ignoreTargetNode": break;
            default:
                throw new Error("Unknown renderMode: " + renderMode);
        }

        if (haveAddedNodesToParent) {
            activateBindingsOnContinuousNodeArray(renderedNodesArray, bindingContext);
            if (options['afterRender'])
                ko.dependencyDetection.ignore(options['afterRender'], null, [renderedNodesArray, bindingContext['$data']]);
        }

        return renderedNodesArray;
    }

    function resolveTemplateName(template, data, context) {
        // The template can be specified as:
        if (ko.isObservable(template)) {
            // 1. An observable, with string value
            return template();
        } else if (typeof template === 'function') {
            // 2. A function of (data, context) returning a string
            return template(data, context);
        } else {
            // 3. A string
            return template;
        }
    }

    ko.renderTemplate = function (template, dataOrBindingContext, options, targetNodeOrNodeArray, renderMode) {
        options = options || {};
        if ((options['templateEngine'] || _templateEngine) == undefined)
            throw new Error("Set a template engine before calling renderTemplate");
        renderMode = renderMode || "replaceChildren";

        if (targetNodeOrNodeArray) {
            var firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);

            var whenToDispose = function () { return (!firstTargetNode) || !ko.utils.domNodeIsAttachedToDocument(firstTargetNode); }; // Passive disposal (on next evaluation)
            var activelyDisposeWhenNodeIsRemoved = (firstTargetNode && renderMode == "replaceNode") ? firstTargetNode.parentNode : firstTargetNode;

            return ko.dependentObservable( // So the DOM is automatically updated when any dependency changes
                function () {
                    // Ensure we've got a proper binding context to work with
                    var bindingContext = (dataOrBindingContext && (dataOrBindingContext instanceof ko.bindingContext))
                        ? dataOrBindingContext
                        : new ko.bindingContext(ko.utils.unwrapObservable(dataOrBindingContext));

                    var templateName = resolveTemplateName(template, bindingContext['$data'], bindingContext),
                        renderedNodesArray = executeTemplate(targetNodeOrNodeArray, renderMode, templateName, bindingContext, options);

                    if (renderMode == "replaceNode") {
                        targetNodeOrNodeArray = renderedNodesArray;
                        firstTargetNode = getFirstNodeFromPossibleArray(targetNodeOrNodeArray);
                    }
                },
                null,
                { disposeWhen: whenToDispose, disposeWhenNodeIsRemoved: activelyDisposeWhenNodeIsRemoved }
            );
        } else {
            // We don't yet have a DOM node to evaluate, so use a memo and render the template later when there is a DOM node
            return ko.memoization.memoize(function (domNode) {
                ko.renderTemplate(template, dataOrBindingContext, options, domNode, "replaceNode");
            });
        }
    };

    ko.renderTemplateForEach = function (template, arrayOrObservableArray, options, targetNode, parentBindingContext) {
        // Since setDomNodeChildrenFromArrayMapping always calls executeTemplateForArrayItem and then
        // activateBindingsCallback for added items, we can store the binding context in the former to use in the latter.
        var arrayItemContext;

        // This will be called by setDomNodeChildrenFromArrayMapping to get the nodes to add to targetNode
        var executeTemplateForArrayItem = function (arrayValue, index) {
            // Support selecting template as a function of the data being rendered
            arrayItemContext = parentBindingContext['createChildContext'](arrayValue, options['as'], function(context) {
                context['$index'] = index;
            });

            var templateName = resolveTemplateName(template, arrayValue, arrayItemContext);
            return executeTemplate(null, "ignoreTargetNode", templateName, arrayItemContext, options);
        }

        // This will be called whenever setDomNodeChildrenFromArrayMapping has added nodes to targetNode
        var activateBindingsCallback = function(arrayValue, addedNodesArray, index) {
            activateBindingsOnContinuousNodeArray(addedNodesArray, arrayItemContext);
            if (options['afterRender'])
                options['afterRender'](addedNodesArray, arrayValue);

            // release the "cache" variable, so that it can be collected by
            // the GC when its value isn't used from within the bindings anymore.
            arrayItemContext = null;
        };

        return ko.dependentObservable(function () {
            var unwrappedArray = ko.utils.unwrapObservable(arrayOrObservableArray) || [];
            if (typeof unwrappedArray.length == "undefined") // Coerce single value into array
                unwrappedArray = [unwrappedArray];

            // Filter out any entries marked as destroyed
            var filteredArray = ko.utils.arrayFilter(unwrappedArray, function(item) {
                return options['includeDestroyed'] || item === undefined || item === null || !ko.utils.unwrapObservable(item['_destroy']);
            });

            // Call setDomNodeChildrenFromArrayMapping, ignoring any observables unwrapped within (most likely from a callback function).
            // If the array items are observables, though, they will be unwrapped in executeTemplateForArrayItem and managed within setDomNodeChildrenFromArrayMapping.
            ko.dependencyDetection.ignore(ko.utils.setDomNodeChildrenFromArrayMapping, null, [targetNode, filteredArray, executeTemplateForArrayItem, options, activateBindingsCallback]);

        }, null, { disposeWhenNodeIsRemoved: targetNode });
    };

    var templateComputedDomDataKey = ko.utils.domData.nextKey();
    function disposeOldComputedAndStoreNewOne(element, newComputed) {
        var oldComputed = ko.utils.domData.get(element, templateComputedDomDataKey);
        if (oldComputed && (typeof(oldComputed.dispose) == 'function'))
            oldComputed.dispose();
        ko.utils.domData.set(element, templateComputedDomDataKey, (newComputed && newComputed.isActive()) ? newComputed : undefined);
    }

    ko.bindingHandlers['template'] = {
        'init': function(element, valueAccessor) {
            // Support anonymous templates
            var bindingValue = ko.utils.unwrapObservable(valueAccessor());
            if (typeof bindingValue == "string" || bindingValue['name']) {
                // It's a named template - clear the element
                ko.virtualElements.emptyNode(element);
            } else if ('nodes' in bindingValue) {
                // We've been given an array of DOM nodes. Save them as the template source.
                // There is no known use case for the node array being an observable array (if the output
                // varies, put that behavior *into* your template - that's what templates are for), and
                // the implementation would be a mess, so assert that it's not observable.
                var nodes = bindingValue['nodes'] || [];
                if (ko.isObservable(nodes)) {
                    throw new Error('The "nodes" option must be a plain, non-observable array.');
                }
                var container = ko.utils.moveCleanedNodesToContainerElement(nodes); // This also removes the nodes from their current parent
                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
            } else {
                // It's an anonymous template - store the element contents, then clear the element
                var templateNodes = ko.virtualElements.childNodes(element),
                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
            }
            return { 'controlsDescendantBindings': true };
        },
        'update': function (element, valueAccessor, allBindings, viewModel, bindingContext) {
            var value = valueAccessor(),
                dataValue,
                options = ko.utils.unwrapObservable(value),
                shouldDisplay = true,
                templateComputed = null,
                templateName;

            if (typeof options == "string") {
                templateName = value;
                options = {};
            } else {
                templateName = options['name'];

                // Support "if"/"ifnot" conditions
                if ('if' in options)
                    shouldDisplay = ko.utils.unwrapObservable(options['if']);
                if (shouldDisplay && 'ifnot' in options)
                    shouldDisplay = !ko.utils.unwrapObservable(options['ifnot']);

                dataValue = ko.utils.unwrapObservable(options['data']);
            }

            if ('foreach' in options) {
                // Render once for each data point (treating data set as empty if shouldDisplay==false)
                var dataArray = (shouldDisplay && options['foreach']) || [];
                templateComputed = ko.renderTemplateForEach(templateName || element, dataArray, options, element, bindingContext);
            } else if (!shouldDisplay) {
                ko.virtualElements.emptyNode(element);
            } else {
                // Render once for this single data point (or use the viewModel if no data was provided)
                var innerBindingContext = ('data' in options) ?
                    bindingContext['createChildContext'](dataValue, options['as']) :  // Given an explitit 'data' value, we create a child binding context for it
                    bindingContext;                                                        // Given no explicit 'data' value, we retain the same binding context
                templateComputed = ko.renderTemplate(templateName || element, innerBindingContext, options, element);
            }

            // It only makes sense to have a single template computed per element (otherwise which one should have its output displayed?)
            disposeOldComputedAndStoreNewOne(element, templateComputed);
        }
    };

    // Anonymous templates can't be rewritten. Give a nice error message if you try to do it.
    ko.expressionRewriting.bindingRewriteValidators['template'] = function(bindingValue) {
        var parsedBindingValue = ko.expressionRewriting.parseObjectLiteral(bindingValue);

        if ((parsedBindingValue.length == 1) && parsedBindingValue[0]['unknown'])
            return null; // It looks like a string literal, not an object literal, so treat it as a named template (which is allowed for rewriting)

        if (ko.expressionRewriting.keyValueArrayContainsKey(parsedBindingValue, "name"))
            return null; // Named templates can be rewritten, so return "no error"
        return "This template engine does not support anonymous templates nested within its templates";
    };

    ko.virtualElements.allowedBindings['template'] = true;
})();

ko.exportSymbol('setTemplateEngine', ko.setTemplateEngine);
ko.exportSymbol('renderTemplate', ko.renderTemplate);
// Go through the items that have been added and deleted and try to find matches between them.
ko.utils.findMovesInArrayComparison = function (left, right, limitFailedCompares) {
    if (left.length && right.length) {
        var failedCompares, l, r, leftItem, rightItem;
        for (failedCompares = l = 0; (!limitFailedCompares || failedCompares < limitFailedCompares) && (leftItem = left[l]); ++l) {
            for (r = 0; rightItem = right[r]; ++r) {
                if (leftItem['value'] === rightItem['value']) {
                    leftItem['moved'] = rightItem['index'];
                    rightItem['moved'] = leftItem['index'];
                    right.splice(r, 1);         // This item is marked as moved; so remove it from right list
                    failedCompares = r = 0;     // Reset failed compares count because we're checking for consecutive failures
                    break;
                }
            }
            failedCompares += r;
        }
    }
};

ko.utils.compareArrays = (function () {
    var statusNotInOld = 'added', statusNotInNew = 'deleted';

    // Simple calculation based on Levenshtein distance.
    function compareArrays(oldArray, newArray, options) {
        // For backward compatibility, if the third arg is actually a bool, interpret
        // it as the old parameter 'dontLimitMoves'. Newer code should use { dontLimitMoves: true }.
        options = (typeof options === 'boolean') ? { 'dontLimitMoves': options } : (options || {});
        oldArray = oldArray || [];
        newArray = newArray || [];

        if (oldArray.length < newArray.length)
            return compareSmallArrayToBigArray(oldArray, newArray, statusNotInOld, statusNotInNew, options);
        else
            return compareSmallArrayToBigArray(newArray, oldArray, statusNotInNew, statusNotInOld, options);
    }

    function compareSmallArrayToBigArray(smlArray, bigArray, statusNotInSml, statusNotInBig, options) {
        var myMin = Math.min,
            myMax = Math.max,
            editDistanceMatrix = [],
            smlIndex, smlIndexMax = smlArray.length,
            bigIndex, bigIndexMax = bigArray.length,
            compareRange = (bigIndexMax - smlIndexMax) || 1,
            maxDistance = smlIndexMax + bigIndexMax + 1,
            thisRow, lastRow,
            bigIndexMaxForRow, bigIndexMinForRow;

        for (smlIndex = 0; smlIndex <= smlIndexMax; smlIndex++) {
            lastRow = thisRow;
            editDistanceMatrix.push(thisRow = []);
            bigIndexMaxForRow = myMin(bigIndexMax, smlIndex + compareRange);
            bigIndexMinForRow = myMax(0, smlIndex - 1);
            for (bigIndex = bigIndexMinForRow; bigIndex <= bigIndexMaxForRow; bigIndex++) {
                if (!bigIndex)
                    thisRow[bigIndex] = smlIndex + 1;
                else if (!smlIndex)  // Top row - transform empty array into new array via additions
                    thisRow[bigIndex] = bigIndex + 1;
                else if (smlArray[smlIndex - 1] === bigArray[bigIndex - 1])
                    thisRow[bigIndex] = lastRow[bigIndex - 1];                  // copy value (no edit)
                else {
                    var northDistance = lastRow[bigIndex] || maxDistance;       // not in big (deletion)
                    var westDistance = thisRow[bigIndex - 1] || maxDistance;    // not in small (addition)
                    thisRow[bigIndex] = myMin(northDistance, westDistance) + 1;
                }
            }
        }

        var editScript = [], meMinusOne, notInSml = [], notInBig = [];
        for (smlIndex = smlIndexMax, bigIndex = bigIndexMax; smlIndex || bigIndex;) {
            meMinusOne = editDistanceMatrix[smlIndex][bigIndex] - 1;
            if (bigIndex && meMinusOne === editDistanceMatrix[smlIndex][bigIndex-1]) {
                notInSml.push(editScript[editScript.length] = {     // added
                    'status': statusNotInSml,
                    'value': bigArray[--bigIndex],
                    'index': bigIndex });
            } else if (smlIndex && meMinusOne === editDistanceMatrix[smlIndex - 1][bigIndex]) {
                notInBig.push(editScript[editScript.length] = {     // deleted
                    'status': statusNotInBig,
                    'value': smlArray[--smlIndex],
                    'index': smlIndex });
            } else {
                --bigIndex;
                --smlIndex;
                if (!options['sparse']) {
                    editScript.push({
                        'status': "retained",
                        'value': bigArray[bigIndex] });
                }
            }
        }

        // Set a limit on the number of consecutive non-matching comparisons; having it a multiple of
        // smlIndexMax keeps the time complexity of this algorithm linear.
        ko.utils.findMovesInArrayComparison(notInBig, notInSml, !options['dontLimitMoves'] && smlIndexMax * 10);

        return editScript.reverse();
    }

    return compareArrays;
})();

ko.exportSymbol('utils.compareArrays', ko.utils.compareArrays);
(function () {
    // Objective:
    // * Given an input array, a container DOM node, and a function from array elements to arrays of DOM nodes,
    //   map the array elements to arrays of DOM nodes, concatenate together all these arrays, and use them to populate the container DOM node
    // * Next time we're given the same combination of things (with the array possibly having mutated), update the container DOM node
    //   so that its children is again the concatenation of the mappings of the array elements, but don't re-map any array elements that we
    //   previously mapped - retain those nodes, and just insert/delete other ones

    // "callbackAfterAddingNodes" will be invoked after any "mapping"-generated nodes are inserted into the container node
    // You can use this, for example, to activate bindings on those nodes.

    function mapNodeAndRefreshWhenChanged(containerNode, mapping, valueToMap, callbackAfterAddingNodes, index) {
        // Map this array value inside a dependentObservable so we re-map when any dependency changes
        var mappedNodes = [];
        var dependentObservable = ko.dependentObservable(function() {
            var newMappedNodes = mapping(valueToMap, index, ko.utils.fixUpContinuousNodeArray(mappedNodes, containerNode)) || [];

            // On subsequent evaluations, just replace the previously-inserted DOM nodes
            if (mappedNodes.length > 0) {
                ko.utils.replaceDomNodes(mappedNodes, newMappedNodes);
                if (callbackAfterAddingNodes)
                    ko.dependencyDetection.ignore(callbackAfterAddingNodes, null, [valueToMap, newMappedNodes, index]);
            }

            // Replace the contents of the mappedNodes array, thereby updating the record
            // of which nodes would be deleted if valueToMap was itself later removed
            mappedNodes.length = 0;
            ko.utils.arrayPushAll(mappedNodes, newMappedNodes);
        }, null, { disposeWhenNodeIsRemoved: containerNode, disposeWhen: function() { return !ko.utils.anyDomNodeIsAttachedToDocument(mappedNodes); } });
        return { mappedNodes : mappedNodes, dependentObservable : (dependentObservable.isActive() ? dependentObservable : undefined) };
    }

    var lastMappingResultDomDataKey = ko.utils.domData.nextKey(),
        deletedItemDummyValue = ko.utils.domData.nextKey();

    ko.utils.setDomNodeChildrenFromArrayMapping = function (domNode, array, mapping, options, callbackAfterAddingNodes) {
        // Compare the provided array against the previous one
        array = array || [];
        options = options || {};
        var isFirstExecution = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) === undefined;
        var lastMappingResult = ko.utils.domData.get(domNode, lastMappingResultDomDataKey) || [];
        var lastArray = ko.utils.arrayMap(lastMappingResult, function (x) { return x.arrayEntry; });
        var editScript = ko.utils.compareArrays(lastArray, array, options['dontLimitMoves']);

        // Build the new mapping result
        var newMappingResult = [];
        var lastMappingResultIndex = 0;
        var newMappingResultIndex = 0;

        var nodesToDelete = [];
        var itemsToProcess = [];
        var itemsForBeforeRemoveCallbacks = [];
        var itemsForMoveCallbacks = [];
        var itemsForAfterAddCallbacks = [];
        var mapData;

        function itemMovedOrRetained(editScriptIndex, oldPosition) {
            mapData = lastMappingResult[oldPosition];
            if (newMappingResultIndex !== oldPosition)
                itemsForMoveCallbacks[editScriptIndex] = mapData;
            // Since updating the index might change the nodes, do so before calling fixUpContinuousNodeArray
            mapData.indexObservable(newMappingResultIndex++);
            ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode);
            newMappingResult.push(mapData);
            itemsToProcess.push(mapData);
        }

        function callCallback(callback, items) {
            if (callback) {
                for (var i = 0, n = items.length; i < n; i++) {
                    if (items[i]) {
                        ko.utils.arrayForEach(items[i].mappedNodes, function(node) {
                            callback(node, i, items[i].arrayEntry);
                        });
                    }
                }
            }
        }

        for (var i = 0, editScriptItem, movedIndex; editScriptItem = editScript[i]; i++) {
            movedIndex = editScriptItem['moved'];
            switch (editScriptItem['status']) {
                case "deleted":
                    if (movedIndex === undefined) {
                        mapData = lastMappingResult[lastMappingResultIndex];

                        // Stop tracking changes to the mapping for these nodes
                        if (mapData.dependentObservable) {
                            mapData.dependentObservable.dispose();
                            mapData.dependentObservable = undefined;
                        }

                        // Queue these nodes for later removal
                        if (ko.utils.fixUpContinuousNodeArray(mapData.mappedNodes, domNode).length) {
                            if (options['beforeRemove']) {
                                newMappingResult.push(mapData);
                                itemsToProcess.push(mapData);
                                if (mapData.arrayEntry === deletedItemDummyValue) {
                                    mapData = null;
                                } else {
                                    itemsForBeforeRemoveCallbacks[i] = mapData;
                                }
                            }
                            if (mapData) {
                                nodesToDelete.push.apply(nodesToDelete, mapData.mappedNodes);
                            }
                        }
                    }
                    lastMappingResultIndex++;
                    break;

                case "retained":
                    itemMovedOrRetained(i, lastMappingResultIndex++);
                    break;

                case "added":
                    if (movedIndex !== undefined) {
                        itemMovedOrRetained(i, movedIndex);
                    } else {
                        mapData = { arrayEntry: editScriptItem['value'], indexObservable: ko.observable(newMappingResultIndex++) };
                        newMappingResult.push(mapData);
                        itemsToProcess.push(mapData);
                        if (!isFirstExecution)
                            itemsForAfterAddCallbacks[i] = mapData;
                    }
                    break;
            }
        }

        // Store a copy of the array items we just considered so we can difference it next time
        ko.utils.domData.set(domNode, lastMappingResultDomDataKey, newMappingResult);

        // Call beforeMove first before any changes have been made to the DOM
        callCallback(options['beforeMove'], itemsForMoveCallbacks);

        // Next remove nodes for deleted items (or just clean if there's a beforeRemove callback)
        ko.utils.arrayForEach(nodesToDelete, options['beforeRemove'] ? ko.cleanNode : ko.removeNode);

        // Next add/reorder the remaining items (will include deleted items if there's a beforeRemove callback)
        for (var i = 0, nextNode = ko.virtualElements.firstChild(domNode), lastNode, node; mapData = itemsToProcess[i]; i++) {
            // Get nodes for newly added items
            if (!mapData.mappedNodes)
                ko.utils.extend(mapData, mapNodeAndRefreshWhenChanged(domNode, mapping, mapData.arrayEntry, callbackAfterAddingNodes, mapData.indexObservable));

            // Put nodes in the right place if they aren't there already
            for (var j = 0; node = mapData.mappedNodes[j]; nextNode = node.nextSibling, lastNode = node, j++) {
                if (node !== nextNode)
                    ko.virtualElements.insertAfter(domNode, node, lastNode);
            }

            // Run the callbacks for newly added nodes (for example, to apply bindings, etc.)
            if (!mapData.initialized && callbackAfterAddingNodes) {
                callbackAfterAddingNodes(mapData.arrayEntry, mapData.mappedNodes, mapData.indexObservable);
                mapData.initialized = true;
            }
        }

        // If there's a beforeRemove callback, call it after reordering.
        // Note that we assume that the beforeRemove callback will usually be used to remove the nodes using
        // some sort of animation, which is why we first reorder the nodes that will be removed. If the
        // callback instead removes the nodes right away, it would be more efficient to skip reordering them.
        // Perhaps we'll make that change in the future if this scenario becomes more common.
        callCallback(options['beforeRemove'], itemsForBeforeRemoveCallbacks);

        // Replace the stored values of deleted items with a dummy value. This provides two benefits: it marks this item
        // as already "removed" so we won't call beforeRemove for it again, and it ensures that the item won't match up
        // with an actual item in the array and appear as "retained" or "moved".
        for (i = 0; i < itemsForBeforeRemoveCallbacks.length; ++i) {
            if (itemsForBeforeRemoveCallbacks[i]) {
                itemsForBeforeRemoveCallbacks[i].arrayEntry = deletedItemDummyValue;
            }
        }

        // Finally call afterMove and afterAdd callbacks
        callCallback(options['afterMove'], itemsForMoveCallbacks);
        callCallback(options['afterAdd'], itemsForAfterAddCallbacks);
    }
})();

ko.exportSymbol('utils.setDomNodeChildrenFromArrayMapping', ko.utils.setDomNodeChildrenFromArrayMapping);
ko.nativeTemplateEngine = function () {
    this['allowTemplateRewriting'] = false;
}

ko.nativeTemplateEngine.prototype = new ko.templateEngine();
ko.nativeTemplateEngine.prototype.constructor = ko.nativeTemplateEngine;
ko.nativeTemplateEngine.prototype['renderTemplateSource'] = function (templateSource, bindingContext, options, templateDocument) {
    var useNodesIfAvailable = !(ko.utils.ieVersion < 9), // IE<9 cloneNode doesn't work properly
        templateNodesFunc = useNodesIfAvailable ? templateSource['nodes'] : null,
        templateNodes = templateNodesFunc ? templateSource['nodes']() : null;

    if (templateNodes) {
        return ko.utils.makeArray(templateNodes.cloneNode(true).childNodes);
    } else {
        var templateText = templateSource['text']();
        return ko.utils.parseHtmlFragment(templateText, templateDocument);
    }
};

ko.nativeTemplateEngine.instance = new ko.nativeTemplateEngine();
ko.setTemplateEngine(ko.nativeTemplateEngine.instance);

ko.exportSymbol('nativeTemplateEngine', ko.nativeTemplateEngine);
(function() {
    ko.jqueryTmplTemplateEngine = function () {
        // Detect which version of jquery-tmpl you're using. Unfortunately jquery-tmpl
        // doesn't expose a version number, so we have to infer it.
        // Note that as of Knockout 1.3, we only support jQuery.tmpl 1.0.0pre and later,
        // which KO internally refers to as version "2", so older versions are no longer detected.
        var jQueryTmplVersion = this.jQueryTmplVersion = (function() {
            if (!jQueryInstance || !(jQueryInstance['tmpl']))
                return 0;
            // Since it exposes no official version number, we use our own numbering system. To be updated as jquery-tmpl evolves.
            try {
                if (jQueryInstance['tmpl']['tag']['tmpl']['open'].toString().indexOf('__') >= 0) {
                    // Since 1.0.0pre, custom tags should append markup to an array called "__"
                    return 2; // Final version of jquery.tmpl
                }
            } catch(ex) { /* Apparently not the version we were looking for */ }

            return 1; // Any older version that we don't support
        })();

        function ensureHasReferencedJQueryTemplates() {
            if (jQueryTmplVersion < 2)
                throw new Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");
        }

        function executeTemplate(compiledTemplate, data, jQueryTemplateOptions) {
            return jQueryInstance['tmpl'](compiledTemplate, data, jQueryTemplateOptions);
        }

        this['renderTemplateSource'] = function(templateSource, bindingContext, options, templateDocument) {
            templateDocument = templateDocument || document;
            options = options || {};
            ensureHasReferencedJQueryTemplates();

            // Ensure we have stored a precompiled version of this template (don't want to reparse on every render)
            var precompiled = templateSource['data']('precompiled');
            if (!precompiled) {
                var templateText = templateSource['text']() || "";
                // Wrap in "with($whatever.koBindingContext) { ... }"
                templateText = "{{ko_with $item.koBindingContext}}" + templateText + "{{/ko_with}}";

                precompiled = jQueryInstance['template'](null, templateText);
                templateSource['data']('precompiled', precompiled);
            }

            var data = [bindingContext['$data']]; // Prewrap the data in an array to stop jquery.tmpl from trying to unwrap any arrays
            var jQueryTemplateOptions = jQueryInstance['extend']({ 'koBindingContext': bindingContext }, options['templateOptions']);

            var resultNodes = executeTemplate(precompiled, data, jQueryTemplateOptions);
            resultNodes['appendTo'](templateDocument.createElement("div")); // Using "appendTo" forces jQuery/jQuery.tmpl to perform necessary cleanup work

            jQueryInstance['fragments'] = {}; // Clear jQuery's fragment cache to avoid a memory leak after a large number of template renders
            return resultNodes;
        };

        this['createJavaScriptEvaluatorBlock'] = function(script) {
            return "{{ko_code ((function() { return " + script + " })()) }}";
        };

        this['addTemplate'] = function(templateName, templateMarkup) {
            document.write("<script type='text/html' id='" + templateName + "'>" + templateMarkup + "<" + "/script>");
        };

        if (jQueryTmplVersion > 0) {
            jQueryInstance['tmpl']['tag']['ko_code'] = {
                open: "__.push($1 || '');"
            };
            jQueryInstance['tmpl']['tag']['ko_with'] = {
                open: "with($1) {",
                close: "} "
            };
        }
    };

    ko.jqueryTmplTemplateEngine.prototype = new ko.templateEngine();
    ko.jqueryTmplTemplateEngine.prototype.constructor = ko.jqueryTmplTemplateEngine;

    // Use this one by default *only if jquery.tmpl is referenced*
    var jqueryTmplTemplateEngineInstance = new ko.jqueryTmplTemplateEngine();
    if (jqueryTmplTemplateEngineInstance.jQueryTmplVersion > 0)
        ko.setTemplateEngine(jqueryTmplTemplateEngineInstance);

    ko.exportSymbol('jqueryTmplTemplateEngine', ko.jqueryTmplTemplateEngine);
})();
}));
}());
})();

},{}],192:[function(require,module,exports){
/*! nanoScrollerJS - v0.8.7 - 2015
* http://jamesflorentino.github.com/nanoScrollerJS/
* Copyright (c) 2015 James Florentino; Licensed MIT */
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    return define(['jquery'], function($) {
      return factory($, window, document);
    });
  } else if (typeof exports === 'object') {
    return module.exports = factory(require('jquery'), window, document);
  } else {
    return factory(jQuery, window, document);
  }
})(function($, window, document) {
  "use strict";
  var BROWSER_IS_IE7, BROWSER_SCROLLBAR_WIDTH, DOMSCROLL, DOWN, DRAG, ENTER, KEYDOWN, KEYUP, MOUSEDOWN, MOUSEENTER, MOUSEMOVE, MOUSEUP, MOUSEWHEEL, NanoScroll, PANEDOWN, RESIZE, SCROLL, SCROLLBAR, TOUCHMOVE, UP, WHEEL, cAF, defaults, getBrowserScrollbarWidth, hasTransform, isFFWithBuggyScrollbar, rAF, transform, _elementStyle, _prefixStyle, _vendor;
  defaults = {

    /**
      a classname for the pane element.
      @property paneClass
      @type String
      @default 'nano-pane'
     */
    paneClass: 'nano-pane',

    /**
      a classname for the slider element.
      @property sliderClass
      @type String
      @default 'nano-slider'
     */
    sliderClass: 'nano-slider',

    /**
      a classname for the content element.
      @property contentClass
      @type String
      @default 'nano-content'
     */
    contentClass: 'nano-content',

    /**
      a setting to enable native scrolling in iOS devices.
      @property iOSNativeScrolling
      @type Boolean
      @default false
     */
    iOSNativeScrolling: false,

    /**
      a setting to prevent the rest of the page being
      scrolled when user scrolls the `.content` element.
      @property preventPageScrolling
      @type Boolean
      @default false
     */
    preventPageScrolling: false,

    /**
      a setting to disable binding to the resize event.
      @property disableResize
      @type Boolean
      @default false
     */
    disableResize: false,

    /**
      a setting to make the scrollbar always visible.
      @property alwaysVisible
      @type Boolean
      @default false
     */
    alwaysVisible: false,

    /**
      a default timeout for the `flash()` method.
      @property flashDelay
      @type Number
      @default 1500
     */
    flashDelay: 1500,

    /**
      a minimum height for the `.slider` element.
      @property sliderMinHeight
      @type Number
      @default 20
     */
    sliderMinHeight: 20,

    /**
      a maximum height for the `.slider` element.
      @property sliderMaxHeight
      @type Number
      @default null
     */
    sliderMaxHeight: null,

    /**
      an alternate document context.
      @property documentContext
      @type Document
      @default null
     */
    documentContext: null,

    /**
      an alternate window context.
      @property windowContext
      @type Window
      @default null
     */
    windowContext: null
  };

  /**
    @property SCROLLBAR
    @type String
    @static
    @final
    @private
   */
  SCROLLBAR = 'scrollbar';

  /**
    @property SCROLL
    @type String
    @static
    @final
    @private
   */
  SCROLL = 'scroll';

  /**
    @property MOUSEDOWN
    @type String
    @final
    @private
   */
  MOUSEDOWN = 'mousedown';

  /**
    @property MOUSEENTER
    @type String
    @final
    @private
   */
  MOUSEENTER = 'mouseenter';

  /**
    @property MOUSEMOVE
    @type String
    @static
    @final
    @private
   */
  MOUSEMOVE = 'mousemove';

  /**
    @property MOUSEWHEEL
    @type String
    @final
    @private
   */
  MOUSEWHEEL = 'mousewheel';

  /**
    @property MOUSEUP
    @type String
    @static
    @final
    @private
   */
  MOUSEUP = 'mouseup';

  /**
    @property RESIZE
    @type String
    @final
    @private
   */
  RESIZE = 'resize';

  /**
    @property DRAG
    @type String
    @static
    @final
    @private
   */
  DRAG = 'drag';

  /**
    @property ENTER
    @type String
    @static
    @final
    @private
   */
  ENTER = 'enter';

  /**
    @property UP
    @type String
    @static
    @final
    @private
   */
  UP = 'up';

  /**
    @property PANEDOWN
    @type String
    @static
    @final
    @private
   */
  PANEDOWN = 'panedown';

  /**
    @property DOMSCROLL
    @type String
    @static
    @final
    @private
   */
  DOMSCROLL = 'DOMMouseScroll';

  /**
    @property DOWN
    @type String
    @static
    @final
    @private
   */
  DOWN = 'down';

  /**
    @property WHEEL
    @type String
    @static
    @final
    @private
   */
  WHEEL = 'wheel';

  /**
    @property KEYDOWN
    @type String
    @static
    @final
    @private
   */
  KEYDOWN = 'keydown';

  /**
    @property KEYUP
    @type String
    @static
    @final
    @private
   */
  KEYUP = 'keyup';

  /**
    @property TOUCHMOVE
    @type String
    @static
    @final
    @private
   */
  TOUCHMOVE = 'touchmove';

  /**
    @property BROWSER_IS_IE7
    @type Boolean
    @static
    @final
    @private
   */
  BROWSER_IS_IE7 = window.navigator.appName === 'Microsoft Internet Explorer' && /msie 7./i.test(window.navigator.appVersion) && window.ActiveXObject;

  /**
    @property BROWSER_SCROLLBAR_WIDTH
    @type Number
    @static
    @default null
    @private
   */
  BROWSER_SCROLLBAR_WIDTH = null;
  rAF = window.requestAnimationFrame;
  cAF = window.cancelAnimationFrame;
  _elementStyle = document.createElement('div').style;
  _vendor = (function() {
    var i, transform, vendor, vendors, _i, _len;
    vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'];
    for (i = _i = 0, _len = vendors.length; _i < _len; i = ++_i) {
      vendor = vendors[i];
      transform = vendors[i] + 'ransform';
      if (transform in _elementStyle) {
        return vendors[i].substr(0, vendors[i].length - 1);
      }
    }
    return false;
  })();
  _prefixStyle = function(style) {
    if (_vendor === false) {
      return false;
    }
    if (_vendor === '') {
      return style;
    }
    return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
  };
  transform = _prefixStyle('transform');
  hasTransform = transform !== false;

  /**
    Returns browser's native scrollbar width
    @method getBrowserScrollbarWidth
    @return {Number} the scrollbar width in pixels
    @static
    @private
   */
  getBrowserScrollbarWidth = function() {
    var outer, outerStyle, scrollbarWidth;
    outer = document.createElement('div');
    outerStyle = outer.style;
    outerStyle.position = 'absolute';
    outerStyle.width = '100px';
    outerStyle.height = '100px';
    outerStyle.overflow = SCROLL;
    outerStyle.top = '-9999px';
    document.body.appendChild(outer);
    scrollbarWidth = outer.offsetWidth - outer.clientWidth;
    document.body.removeChild(outer);
    return scrollbarWidth;
  };
  isFFWithBuggyScrollbar = function() {
    var isOSXFF, ua, version;
    ua = window.navigator.userAgent;
    isOSXFF = /(?=.+Mac OS X)(?=.+Firefox)/.test(ua);
    if (!isOSXFF) {
      return false;
    }
    version = /Firefox\/\d{2}\./.exec(ua);
    if (version) {
      version = version[0].replace(/\D+/g, '');
    }
    return isOSXFF && +version > 23;
  };

  /**
    @class NanoScroll
    @param element {HTMLElement|Node} the main element
    @param options {Object} nanoScroller's options
    @constructor
   */
  NanoScroll = (function() {
    function NanoScroll(el, options) {
      this.el = el;
      this.options = options;
      BROWSER_SCROLLBAR_WIDTH || (BROWSER_SCROLLBAR_WIDTH = getBrowserScrollbarWidth());
      this.$el = $(this.el);
      this.doc = $(this.options.documentContext || document);
      this.win = $(this.options.windowContext || window);
      this.body = this.doc.find('body');
      this.$content = this.$el.children("." + this.options.contentClass);
      this.$content.attr('tabindex', this.options.tabIndex || 0);
      this.content = this.$content[0];
      this.previousPosition = 0;
      if (this.options.iOSNativeScrolling && (this.el.style.WebkitOverflowScrolling != null)) {
        this.nativeScrolling();
      } else {
        this.generate();
      }
      this.createEvents();
      this.addEvents();
      this.reset();
    }


    /**
      Prevents the rest of the page being scrolled
      when user scrolls the `.nano-content` element.
      @method preventScrolling
      @param event {Event}
      @param direction {String} Scroll direction (up or down)
      @private
     */

    NanoScroll.prototype.preventScrolling = function(e, direction) {
      if (!this.isActive) {
        return;
      }
      if (e.type === DOMSCROLL) {
        if (direction === DOWN && e.originalEvent.detail > 0 || direction === UP && e.originalEvent.detail < 0) {
          e.preventDefault();
        }
      } else if (e.type === MOUSEWHEEL) {
        if (!e.originalEvent || !e.originalEvent.wheelDelta) {
          return;
        }
        if (direction === DOWN && e.originalEvent.wheelDelta < 0 || direction === UP && e.originalEvent.wheelDelta > 0) {
          e.preventDefault();
        }
      }
    };


    /**
      Enable iOS native scrolling
      @method nativeScrolling
      @private
     */

    NanoScroll.prototype.nativeScrolling = function() {
      this.$content.css({
        WebkitOverflowScrolling: 'touch'
      });
      this.iOSNativeScrolling = true;
      this.isActive = true;
    };


    /**
      Updates those nanoScroller properties that
      are related to current scrollbar position.
      @method updateScrollValues
      @private
     */

    NanoScroll.prototype.updateScrollValues = function() {
      var content, direction;
      content = this.content;
      this.maxScrollTop = content.scrollHeight - content.clientHeight;
      this.prevScrollTop = this.contentScrollTop || 0;
      this.contentScrollTop = content.scrollTop;
      direction = this.contentScrollTop > this.previousPosition ? "down" : this.contentScrollTop < this.previousPosition ? "up" : "same";
      this.previousPosition = this.contentScrollTop;
      if (direction !== "same") {
        this.$el.trigger('update', {
          position: this.contentScrollTop,
          maximum: this.maxScrollTop,
          direction: direction
        });
      }
      if (!this.iOSNativeScrolling) {
        this.maxSliderTop = this.paneHeight - this.sliderHeight;
        this.sliderTop = this.maxScrollTop === 0 ? 0 : this.contentScrollTop * this.maxSliderTop / this.maxScrollTop;
      }
    };


    /**
      Updates CSS styles for current scroll position.
      Uses CSS 2d transfroms and `window.requestAnimationFrame` if available.
      @method setOnScrollStyles
      @private
     */

    NanoScroll.prototype.setOnScrollStyles = function() {
      var cssValue;
      if (hasTransform) {
        cssValue = {};
        cssValue[transform] = "translate(0, " + this.sliderTop + "px)";
      } else {
        cssValue = {
          top: this.sliderTop
        };
      }
      if (rAF) {
        if (cAF && this.scrollRAF) {
          cAF(this.scrollRAF);
        }
        this.scrollRAF = rAF((function(_this) {
          return function() {
            _this.scrollRAF = null;
            return _this.slider.css(cssValue);
          };
        })(this));
      } else {
        this.slider.css(cssValue);
      }
    };


    /**
      Creates event related methods
      @method createEvents
      @private
     */

    NanoScroll.prototype.createEvents = function() {
      this.events = {
        down: (function(_this) {
          return function(e) {
            _this.isBeingDragged = true;
            _this.offsetY = e.pageY - _this.slider.offset().top;
            if (!_this.slider.is(e.target)) {
              _this.offsetY = 0;
            }
            _this.pane.addClass('active');
            _this.doc.bind(MOUSEMOVE, _this.events[DRAG]).bind(MOUSEUP, _this.events[UP]);
            _this.body.bind(MOUSEENTER, _this.events[ENTER]);
            return false;
          };
        })(this),
        drag: (function(_this) {
          return function(e) {
            _this.sliderY = e.pageY - _this.$el.offset().top - _this.paneTop - (_this.offsetY || _this.sliderHeight * 0.5);
            _this.scroll();
            if (_this.contentScrollTop >= _this.maxScrollTop && _this.prevScrollTop !== _this.maxScrollTop) {
              _this.$el.trigger('scrollend');
            } else if (_this.contentScrollTop === 0 && _this.prevScrollTop !== 0) {
              _this.$el.trigger('scrolltop');
            }
            return false;
          };
        })(this),
        up: (function(_this) {
          return function(e) {
            _this.isBeingDragged = false;
            _this.pane.removeClass('active');
            _this.doc.unbind(MOUSEMOVE, _this.events[DRAG]).unbind(MOUSEUP, _this.events[UP]);
            _this.body.unbind(MOUSEENTER, _this.events[ENTER]);
            return false;
          };
        })(this),
        resize: (function(_this) {
          return function(e) {
            _this.reset();
          };
        })(this),
        panedown: (function(_this) {
          return function(e) {
            _this.sliderY = (e.offsetY || e.originalEvent.layerY) - (_this.sliderHeight * 0.5);
            _this.scroll();
            _this.events.down(e);
            return false;
          };
        })(this),
        scroll: (function(_this) {
          return function(e) {
            _this.updateScrollValues();
            if (_this.isBeingDragged) {
              return;
            }
            if (!_this.iOSNativeScrolling) {
              _this.sliderY = _this.sliderTop;
              _this.setOnScrollStyles();
            }
            if (e == null) {
              return;
            }
            if (_this.contentScrollTop >= _this.maxScrollTop) {
              if (_this.options.preventPageScrolling) {
                _this.preventScrolling(e, DOWN);
              }
              if (_this.prevScrollTop !== _this.maxScrollTop) {
                _this.$el.trigger('scrollend');
              }
            } else if (_this.contentScrollTop === 0) {
              if (_this.options.preventPageScrolling) {
                _this.preventScrolling(e, UP);
              }
              if (_this.prevScrollTop !== 0) {
                _this.$el.trigger('scrolltop');
              }
            }
          };
        })(this),
        wheel: (function(_this) {
          return function(e) {
            var delta;
            if (e == null) {
              return;
            }
            delta = e.delta || e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail || (e.originalEvent && -e.originalEvent.detail);
            if (delta) {
              _this.sliderY += -delta / 3;
            }
            _this.scroll();
            return false;
          };
        })(this),
        enter: (function(_this) {
          return function(e) {
            var _ref;
            if (!_this.isBeingDragged) {
              return;
            }
            if ((e.buttons || e.which) !== 1) {
              return (_ref = _this.events)[UP].apply(_ref, arguments);
            }
          };
        })(this)
      };
    };


    /**
      Adds event listeners with jQuery.
      @method addEvents
      @private
     */

    NanoScroll.prototype.addEvents = function() {
      var events;
      this.removeEvents();
      events = this.events;
      if (!this.options.disableResize) {
        this.win.bind(RESIZE, events[RESIZE]);
      }
      if (!this.iOSNativeScrolling) {
        this.slider.bind(MOUSEDOWN, events[DOWN]);
        this.pane.bind(MOUSEDOWN, events[PANEDOWN]).bind("" + MOUSEWHEEL + " " + DOMSCROLL, events[WHEEL]);
      }
      this.$content.bind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
    };


    /**
      Removes event listeners with jQuery.
      @method removeEvents
      @private
     */

    NanoScroll.prototype.removeEvents = function() {
      var events;
      events = this.events;
      this.win.unbind(RESIZE, events[RESIZE]);
      if (!this.iOSNativeScrolling) {
        this.slider.unbind();
        this.pane.unbind();
      }
      this.$content.unbind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
    };


    /**
      Generates nanoScroller's scrollbar and elements for it.
      @method generate
      @chainable
      @private
     */

    NanoScroll.prototype.generate = function() {
      var contentClass, cssRule, currentPadding, options, pane, paneClass, sliderClass;
      options = this.options;
      paneClass = options.paneClass, sliderClass = options.sliderClass, contentClass = options.contentClass;
      if (!(pane = this.$el.children("." + paneClass)).length && !pane.children("." + sliderClass).length) {
        this.$el.append("<div class=\"" + paneClass + "\"><div class=\"" + sliderClass + "\" /></div>");
      }
      this.pane = this.$el.children("." + paneClass);
      this.slider = this.pane.find("." + sliderClass);
      if (BROWSER_SCROLLBAR_WIDTH === 0 && isFFWithBuggyScrollbar()) {
        currentPadding = window.getComputedStyle(this.content, null).getPropertyValue('padding-right').replace(/[^0-9.]+/g, '');
        cssRule = {
          right: -14,
          paddingRight: +currentPadding + 14
        };
      } else if (BROWSER_SCROLLBAR_WIDTH) {
        cssRule = {
          right: -BROWSER_SCROLLBAR_WIDTH
        };
        this.$el.addClass('has-scrollbar');
      }
      if (cssRule != null) {
        this.$content.css(cssRule);
      }
      return this;
    };


    /**
      @method restore
      @private
     */

    NanoScroll.prototype.restore = function() {
      this.stopped = false;
      if (!this.iOSNativeScrolling) {
        this.pane.show();
      }
      this.addEvents();
    };


    /**
      Resets nanoScroller's scrollbar.
      @method reset
      @chainable
      @example
          $(".nano").nanoScroller();
     */

    NanoScroll.prototype.reset = function() {
      var content, contentHeight, contentPosition, contentStyle, contentStyleOverflowY, paneBottom, paneHeight, paneOuterHeight, paneTop, parentMaxHeight, right, sliderHeight;
      if (this.iOSNativeScrolling) {
        this.contentHeight = this.content.scrollHeight;
        return;
      }
      if (!this.$el.find("." + this.options.paneClass).length) {
        this.generate().stop();
      }
      if (this.stopped) {
        this.restore();
      }
      content = this.content;
      contentStyle = content.style;
      contentStyleOverflowY = contentStyle.overflowY;
      if (BROWSER_IS_IE7) {
        this.$content.css({
          height: this.$content.height()
        });
      }
      contentHeight = content.scrollHeight + BROWSER_SCROLLBAR_WIDTH;
      parentMaxHeight = parseInt(this.$el.css("max-height"), 10);
      if (parentMaxHeight > 0) {
        this.$el.height("");
        this.$el.height(content.scrollHeight > parentMaxHeight ? parentMaxHeight : content.scrollHeight);
      }
      paneHeight = this.pane.outerHeight(false);
      paneTop = parseInt(this.pane.css('top'), 10);
      paneBottom = parseInt(this.pane.css('bottom'), 10);
      paneOuterHeight = paneHeight + paneTop + paneBottom;
      sliderHeight = Math.round(paneOuterHeight / contentHeight * paneHeight);
      if (sliderHeight < this.options.sliderMinHeight) {
        sliderHeight = this.options.sliderMinHeight;
      } else if ((this.options.sliderMaxHeight != null) && sliderHeight > this.options.sliderMaxHeight) {
        sliderHeight = this.options.sliderMaxHeight;
      }
      if (contentStyleOverflowY === SCROLL && contentStyle.overflowX !== SCROLL) {
        sliderHeight += BROWSER_SCROLLBAR_WIDTH;
      }
      this.maxSliderTop = paneOuterHeight - sliderHeight;
      this.contentHeight = contentHeight;
      this.paneHeight = paneHeight;
      this.paneOuterHeight = paneOuterHeight;
      this.sliderHeight = sliderHeight;
      this.paneTop = paneTop;
      this.slider.height(sliderHeight);
      this.events.scroll();
      this.pane.show();
      this.isActive = true;
      if ((content.scrollHeight === content.clientHeight) || (this.pane.outerHeight(true) >= content.scrollHeight && contentStyleOverflowY !== SCROLL)) {
        this.pane.hide();
        this.isActive = false;
      } else if (this.el.clientHeight === content.scrollHeight && contentStyleOverflowY === SCROLL) {
        this.slider.hide();
      } else {
        this.slider.show();
      }
      this.pane.css({
        opacity: (this.options.alwaysVisible ? 1 : ''),
        visibility: (this.options.alwaysVisible ? 'visible' : '')
      });
      contentPosition = this.$content.css('position');
      if (contentPosition === 'static' || contentPosition === 'relative') {
        right = parseInt(this.$content.css('right'), 10);
        if (right) {
          this.$content.css({
            right: '',
            marginRight: right
          });
        }
      }
      return this;
    };


    /**
      @method scroll
      @private
      @example
          $(".nano").nanoScroller({ scroll: 'top' });
     */

    NanoScroll.prototype.scroll = function() {
      if (!this.isActive) {
        return;
      }
      this.sliderY = Math.max(0, this.sliderY);
      this.sliderY = Math.min(this.maxSliderTop, this.sliderY);
      this.$content.scrollTop(this.maxScrollTop * this.sliderY / this.maxSliderTop);
      if (!this.iOSNativeScrolling) {
        this.updateScrollValues();
        this.setOnScrollStyles();
      }
      return this;
    };


    /**
      Scroll at the bottom with an offset value
      @method scrollBottom
      @param offsetY {Number}
      @chainable
      @example
          $(".nano").nanoScroller({ scrollBottom: value });
     */

    NanoScroll.prototype.scrollBottom = function(offsetY) {
      if (!this.isActive) {
        return;
      }
      this.$content.scrollTop(this.contentHeight - this.$content.height() - offsetY).trigger(MOUSEWHEEL);
      this.stop().restore();
      return this;
    };


    /**
      Scroll at the top with an offset value
      @method scrollTop
      @param offsetY {Number}
      @chainable
      @example
          $(".nano").nanoScroller({ scrollTop: value });
     */

    NanoScroll.prototype.scrollTop = function(offsetY) {
      if (!this.isActive) {
        return;
      }
      this.$content.scrollTop(+offsetY).trigger(MOUSEWHEEL);
      this.stop().restore();
      return this;
    };


    /**
      Scroll to an element
      @method scrollTo
      @param node {Node} A node to scroll to.
      @chainable
      @example
          $(".nano").nanoScroller({ scrollTo: $('#a_node') });
     */

    NanoScroll.prototype.scrollTo = function(node) {
      if (!this.isActive) {
        return;
      }
      this.scrollTop(this.$el.find(node).get(0).offsetTop);
      return this;
    };


    /**
      To stop the operation.
      This option will tell the plugin to disable all event bindings and hide the gadget scrollbar from the UI.
      @method stop
      @chainable
      @example
          $(".nano").nanoScroller({ stop: true });
     */

    NanoScroll.prototype.stop = function() {
      if (cAF && this.scrollRAF) {
        cAF(this.scrollRAF);
        this.scrollRAF = null;
      }
      this.stopped = true;
      this.removeEvents();
      if (!this.iOSNativeScrolling) {
        this.pane.hide();
      }
      return this;
    };


    /**
      Destroys nanoScroller and restores browser's native scrollbar.
      @method destroy
      @chainable
      @example
          $(".nano").nanoScroller({ destroy: true });
     */

    NanoScroll.prototype.destroy = function() {
      if (!this.stopped) {
        this.stop();
      }
      if (!this.iOSNativeScrolling && this.pane.length) {
        this.pane.remove();
      }
      if (BROWSER_IS_IE7) {
        this.$content.height('');
      }
      this.$content.removeAttr('tabindex');
      if (this.$el.hasClass('has-scrollbar')) {
        this.$el.removeClass('has-scrollbar');
        this.$content.css({
          right: ''
        });
      }
      return this;
    };


    /**
      To flash the scrollbar gadget for an amount of time defined in plugin settings (defaults to 1,5s).
      Useful if you want to show the user (e.g. on pageload) that there is more content waiting for him.
      @method flash
      @chainable
      @example
          $(".nano").nanoScroller({ flash: true });
     */

    NanoScroll.prototype.flash = function() {
      if (this.iOSNativeScrolling) {
        return;
      }
      if (!this.isActive) {
        return;
      }
      this.reset();
      this.pane.addClass('flashed');
      setTimeout((function(_this) {
        return function() {
          _this.pane.removeClass('flashed');
        };
      })(this), this.options.flashDelay);
      return this;
    };

    return NanoScroll;

  })();
  $.fn.nanoScroller = function(settings) {
    return this.each(function() {
      var options, scrollbar;
      if (!(scrollbar = this.nanoscroller)) {
        options = $.extend({}, defaults, settings);
        this.nanoscroller = scrollbar = new NanoScroll(this, options);
      }
      if (settings && typeof settings === "object") {
        $.extend(scrollbar.options, settings);
        if (settings.scrollBottom != null) {
          return scrollbar.scrollBottom(settings.scrollBottom);
        }
        if (settings.scrollTop != null) {
          return scrollbar.scrollTop(settings.scrollTop);
        }
        if (settings.scrollTo) {
          return scrollbar.scrollTo(settings.scrollTo);
        }
        if (settings.scroll === 'bottom') {
          return scrollbar.scrollBottom(0);
        }
        if (settings.scroll === 'top') {
          return scrollbar.scrollTop(0);
        }
        if (settings.scroll && settings.scroll instanceof $) {
          return scrollbar.scrollTo(settings.scroll);
        }
        if (settings.stop) {
          return scrollbar.stop();
        }
        if (settings.destroy) {
          return scrollbar.destroy();
        }
        if (settings.flash) {
          return scrollbar.flash();
        }
      }
      return scrollbar.reset();
    });
  };
  $.fn.nanoScroller.Constructor = NanoScroll;
});



},{"jquery":214}],193:[function(require,module,exports){
/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
 * @license MIT */

;(function(root, factory) {

  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root.NProgress = factory();
  }

})(this, function() {
  var NProgress = {};

  NProgress.version = '0.2.0';

  var Settings = NProgress.settings = {
    minimum: 0.08,
    easing: 'ease',
    positionUsing: '',
    speed: 200,
    trickle: true,
    trickleRate: 0.02,
    trickleSpeed: 800,
    showSpinner: true,
    barSelector: '[role="bar"]',
    spinnerSelector: '[role="spinner"]',
    parent: 'body',
    template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
  };

  /**
   * Updates configuration.
   *
   *     NProgress.configure({
   *       minimum: 0.1
   *     });
   */
  NProgress.configure = function(options) {
    var key, value;
    for (key in options) {
      value = options[key];
      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
    }

    return this;
  };

  /**
   * Last number.
   */

  NProgress.status = null;

  /**
   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
   *
   *     NProgress.set(0.4);
   *     NProgress.set(1.0);
   */

  NProgress.set = function(n) {
    var started = NProgress.isStarted();

    n = clamp(n, Settings.minimum, 1);
    NProgress.status = (n === 1 ? null : n);

    var progress = NProgress.render(!started),
        bar      = progress.querySelector(Settings.barSelector),
        speed    = Settings.speed,
        ease     = Settings.easing;

    progress.offsetWidth; /* Repaint */

    queue(function(next) {
      // Set positionUsing if it hasn't already been set
      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();

      // Add transition
      css(bar, barPositionCSS(n, speed, ease));

      if (n === 1) {
        // Fade out
        css(progress, { 
          transition: 'none', 
          opacity: 1 
        });
        progress.offsetWidth; /* Repaint */

        setTimeout(function() {
          css(progress, { 
            transition: 'all ' + speed + 'ms linear', 
            opacity: 0 
          });
          setTimeout(function() {
            NProgress.remove();
            next();
          }, speed);
        }, speed);
      } else {
        setTimeout(next, speed);
      }
    });

    return this;
  };

  NProgress.isStarted = function() {
    return typeof NProgress.status === 'number';
  };

  /**
   * Shows the progress bar.
   * This is the same as setting the status to 0%, except that it doesn't go backwards.
   *
   *     NProgress.start();
   *
   */
  NProgress.start = function() {
    if (!NProgress.status) NProgress.set(0);

    var work = function() {
      setTimeout(function() {
        if (!NProgress.status) return;
        NProgress.trickle();
        work();
      }, Settings.trickleSpeed);
    };

    if (Settings.trickle) work();

    return this;
  };

  /**
   * Hides the progress bar.
   * This is the *sort of* the same as setting the status to 100%, with the
   * difference being `done()` makes some placebo effect of some realistic motion.
   *
   *     NProgress.done();
   *
   * If `true` is passed, it will show the progress bar even if its hidden.
   *
   *     NProgress.done(true);
   */

  NProgress.done = function(force) {
    if (!force && !NProgress.status) return this;

    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
  };

  /**
   * Increments by a random amount.
   */

  NProgress.inc = function(amount) {
    var n = NProgress.status;

    if (!n) {
      return NProgress.start();
    } else {
      if (typeof amount !== 'number') {
        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);
      }

      n = clamp(n + amount, 0, 0.994);
      return NProgress.set(n);
    }
  };

  NProgress.trickle = function() {
    return NProgress.inc(Math.random() * Settings.trickleRate);
  };

  /**
   * Waits for all supplied jQuery promises and
   * increases the progress as the promises resolve.
   *
   * @param $promise jQUery Promise
   */
  (function() {
    var initial = 0, current = 0;

    NProgress.promise = function($promise) {
      if (!$promise || $promise.state() === "resolved") {
        return this;
      }

      if (current === 0) {
        NProgress.start();
      }

      initial++;
      current++;

      $promise.always(function() {
        current--;
        if (current === 0) {
            initial = 0;
            NProgress.done();
        } else {
            NProgress.set((initial - current) / initial);
        }
      });

      return this;
    };

  })();

  /**
   * (Internal) renders the progress bar markup based on the `template`
   * setting.
   */

  NProgress.render = function(fromStart) {
    if (NProgress.isRendered()) return document.getElementById('nprogress');

    addClass(document.documentElement, 'nprogress-busy');
    
    var progress = document.createElement('div');
    progress.id = 'nprogress';
    progress.innerHTML = Settings.template;

    var bar      = progress.querySelector(Settings.barSelector),
        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
        parent   = document.querySelector(Settings.parent),
        spinner;
    
    css(bar, {
      transition: 'all 0 linear',
      transform: 'translate3d(' + perc + '%,0,0)'
    });

    if (!Settings.showSpinner) {
      spinner = progress.querySelector(Settings.spinnerSelector);
      spinner && removeElement(spinner);
    }

    if (parent != document.body) {
      addClass(parent, 'nprogress-custom-parent');
    }

    parent.appendChild(progress);
    return progress;
  };

  /**
   * Removes the element. Opposite of render().
   */

  NProgress.remove = function() {
    removeClass(document.documentElement, 'nprogress-busy');
    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');
    var progress = document.getElementById('nprogress');
    progress && removeElement(progress);
  };

  /**
   * Checks if the progress bar is rendered.
   */

  NProgress.isRendered = function() {
    return !!document.getElementById('nprogress');
  };

  /**
   * Determine which positioning CSS rule to use.
   */

  NProgress.getPositioningCSS = function() {
    // Sniff on document.body.style
    var bodyStyle = document.body.style;

    // Sniff prefixes
    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
                       ('MozTransform' in bodyStyle) ? 'Moz' :
                       ('msTransform' in bodyStyle) ? 'ms' :
                       ('OTransform' in bodyStyle) ? 'O' : '';

    if (vendorPrefix + 'Perspective' in bodyStyle) {
      // Modern browsers with 3D support, e.g. Webkit, IE10
      return 'translate3d';
    } else if (vendorPrefix + 'Transform' in bodyStyle) {
      // Browsers without 3D support, e.g. IE9
      return 'translate';
    } else {
      // Browsers without translate() support, e.g. IE7-8
      return 'margin';
    }
  };

  /**
   * Helpers
   */

  function clamp(n, min, max) {
    if (n < min) return min;
    if (n > max) return max;
    return n;
  }

  /**
   * (Internal) converts a percentage (`0..1`) to a bar translateX
   * percentage (`-100%..0%`).
   */

  function toBarPerc(n) {
    return (-1 + n) * 100;
  }


  /**
   * (Internal) returns the correct CSS for changing the bar's
   * position given an n percentage, and speed and ease from Settings
   */

  function barPositionCSS(n, speed, ease) {
    var barCSS;

    if (Settings.positionUsing === 'translate3d') {
      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
    } else if (Settings.positionUsing === 'translate') {
      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
    } else {
      barCSS = { 'margin-left': toBarPerc(n)+'%' };
    }

    barCSS.transition = 'all '+speed+'ms '+ease;

    return barCSS;
  }

  /**
   * (Internal) Queues a function to be executed.
   */

  var queue = (function() {
    var pending = [];
    
    function next() {
      var fn = pending.shift();
      if (fn) {
        fn(next);
      }
    }

    return function(fn) {
      pending.push(fn);
      if (pending.length == 1) next();
    };
  })();

  /**
   * (Internal) Applies css properties to an element, similar to the jQuery 
   * css method.
   *
   * While this helper does assist with vendor prefixed property names, it 
   * does not perform any manipulation of values prior to setting styles.
   */

  var css = (function() {
    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
        cssProps    = {};

    function camelCase(string) {
      return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
        return letter.toUpperCase();
      });
    }

    function getVendorProp(name) {
      var style = document.body.style;
      if (name in style) return name;

      var i = cssPrefixes.length,
          capName = name.charAt(0).toUpperCase() + name.slice(1),
          vendorName;
      while (i--) {
        vendorName = cssPrefixes[i] + capName;
        if (vendorName in style) return vendorName;
      }

      return name;
    }

    function getStyleProp(name) {
      name = camelCase(name);
      return cssProps[name] || (cssProps[name] = getVendorProp(name));
    }

    function applyCss(element, prop, value) {
      prop = getStyleProp(prop);
      element.style[prop] = value;
    }

    return function(element, properties) {
      var args = arguments,
          prop, 
          value;

      if (args.length == 2) {
        for (prop in properties) {
          value = properties[prop];
          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
        }
      } else {
        applyCss(element, args[1], args[2]);
      }
    }
  })();

  /**
   * (Internal) Determines if an element or space separated list of class names contains a class name.
   */

  function hasClass(element, name) {
    var list = typeof element == 'string' ? element : classList(element);
    return list.indexOf(' ' + name + ' ') >= 0;
  }

  /**
   * (Internal) Adds a class to an element.
   */

  function addClass(element, name) {
    var oldList = classList(element),
        newList = oldList + name;

    if (hasClass(oldList, name)) return; 

    // Trim the opening space.
    element.className = newList.substring(1);
  }

  /**
   * (Internal) Removes a class from an element.
   */

  function removeClass(element, name) {
    var oldList = classList(element),
        newList;

    if (!hasClass(element, name)) return;

    // Replace the class name.
    newList = oldList.replace(' ' + name + ' ', ' ');

    // Trim the opening and closing spaces.
    element.className = newList.substring(1, newList.length - 1);
  }

  /**
   * (Internal) Gets a space separated list of the class names on the element. 
   * The list is wrapped with a single space on each end to facilitate finding 
   * matches within the list.
   */

  function classList(element) {
    return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' ');
  }

  /**
   * (Internal) Removes an element from the DOM.
   */

  function removeElement(element) {
    element && element.parentNode && element.parentNode.removeChild(element);
  }

  return NProgress;
});

},{}],194:[function(require,module,exports){
/*!
  * $script.js JS loader & dependency manager
  * https://github.com/ded/script.js
  * (c) Dustin Diaz 2014 | License MIT
  */

(function (name, definition) {
  if (typeof module != 'undefined' && module.exports) module.exports = definition()
  else if (typeof define == 'function' && define.amd) define(definition)
  else this[name] = definition()
})('$script', function () {
  var doc = document
    , head = doc.getElementsByTagName('head')[0]
    , s = 'string'
    , f = false
    , push = 'push'
    , readyState = 'readyState'
    , onreadystatechange = 'onreadystatechange'
    , list = {}
    , ids = {}
    , delay = {}
    , scripts = {}
    , scriptpath
    , urlArgs

  function every(ar, fn) {
    for (var i = 0, j = ar.length; i < j; ++i) if (!fn(ar[i])) return f
    return 1
  }
  function each(ar, fn) {
    every(ar, function (el) {
      return !fn(el)
    })
  }

  function $script(paths, idOrDone, optDone) {
    paths = paths[push] ? paths : [paths]
    var idOrDoneIsDone = idOrDone && idOrDone.call
      , done = idOrDoneIsDone ? idOrDone : optDone
      , id = idOrDoneIsDone ? paths.join('') : idOrDone
      , queue = paths.length
    function loopFn(item) {
      return item.call ? item() : list[item]
    }
    function callback() {
      if (!--queue) {
        list[id] = 1
        done && done()
        for (var dset in delay) {
          every(dset.split('|'), loopFn) && !each(delay[dset], loopFn) && (delay[dset] = [])
        }
      }
    }
    setTimeout(function () {
      each(paths, function loading(path, force) {
        if (path === null) return callback()
        
        if (!force && !/^https?:\/\//.test(path) && scriptpath) {
          path = (path.indexOf('.js') === -1) ? scriptpath + path + '.js' : scriptpath + path;
        }
        
        if (scripts[path]) {
          if (id) ids[id] = 1
          return (scripts[path] == 2) ? callback() : setTimeout(function () { loading(path, true) }, 0)
        }

        scripts[path] = 1
        if (id) ids[id] = 1
        create(path, callback)
      })
    }, 0)
    return $script
  }

  function create(path, fn) {
    var el = doc.createElement('script'), loaded
    el.onload = el.onerror = el[onreadystatechange] = function () {
      if ((el[readyState] && !(/^c|loade/.test(el[readyState]))) || loaded) return;
      el.onload = el[onreadystatechange] = null
      loaded = 1
      scripts[path] = 2
      fn()
    }
    el.async = 1
    el.src = urlArgs ? path + (path.indexOf('?') === -1 ? '?' : '&') + urlArgs : path;
    head.insertBefore(el, head.lastChild)
  }

  $script.get = create

  $script.order = function (scripts, id, done) {
    (function callback(s) {
      s = scripts.shift()
      !scripts.length ? $script(s, id, done) : $script(s, callback)
    }())
  }

  $script.path = function (p) {
    scriptpath = p
  }
  $script.urlArgs = function (str) {
    urlArgs = str;
  }
  $script.ready = function (deps, ready, req) {
    deps = deps[push] ? deps : [deps]
    var missing = [];
    !each(deps, function (dep) {
      list[dep] || missing[push](dep);
    }) && every(deps, function (dep) {return list[dep]}) ?
      ready() : !function (key) {
      delay[key] = delay[key] || []
      delay[key][push](ready)
      req && req(missing)
    }(deps.join('|'))
    return $script
  }

  $script.done = function (idOrDone) {
    $script([null], idOrDone)
  }

  return $script
});

},{}],195:[function(require,module,exports){
/* jquery.signalR.core.js */
/*global window:false */
/*!
 * ASP.NET SignalR JavaScript Library v2.2.0
 * http://signalr.net/
 *
 * Copyright (C) Microsoft Corporation. All rights reserved.
 *
 */

/// <reference path="Scripts/jquery-1.6.4.js" />
/// <reference path="jquery.signalR.version.js" />
(function ($, window, undefined) {

    var resources = {
        nojQuery: "jQuery was not found. Please ensure jQuery is referenced before the SignalR client JavaScript file.",
        noTransportOnInit: "No transport could be initialized successfully. Try specifying a different transport or none at all for auto initialization.",
        errorOnNegotiate: "Error during negotiation request.",
        stoppedWhileLoading: "The connection was stopped during page load.",
        stoppedWhileNegotiating: "The connection was stopped during the negotiate request.",
        errorParsingNegotiateResponse: "Error parsing negotiate response.",
        errorDuringStartRequest: "Error during start request. Stopping the connection.",
        stoppedDuringStartRequest: "The connection was stopped during the start request.",
        errorParsingStartResponse: "Error parsing start response: '{0}'. Stopping the connection.",
        invalidStartResponse: "Invalid start response: '{0}'. Stopping the connection.",
        protocolIncompatible: "You are using a version of the client that isn't compatible with the server. Client version {0}, server version {1}.",
        sendFailed: "Send failed.",
        parseFailed: "Failed at parsing response: {0}",
        longPollFailed: "Long polling request failed.",
        eventSourceFailedToConnect: "EventSource failed to connect.",
        eventSourceError: "Error raised by EventSource",
        webSocketClosed: "WebSocket closed.",
        pingServerFailedInvalidResponse: "Invalid ping response when pinging server: '{0}'.",
        pingServerFailed: "Failed to ping server.",
        pingServerFailedStatusCode: "Failed to ping server.  Server responded with status code {0}, stopping the connection.",
        pingServerFailedParse: "Failed to parse ping server response, stopping the connection.",
        noConnectionTransport: "Connection is in an invalid state, there is no transport active.",
        webSocketsInvalidState: "The Web Socket transport is in an invalid state, transitioning into reconnecting.",
        reconnectTimeout: "Couldn't reconnect within the configured timeout of {0} ms, disconnecting.",
        reconnectWindowTimeout: "The client has been inactive since {0} and it has exceeded the inactivity timeout of {1} ms. Stopping the connection."
    };

    if (typeof ($) !== "function") {
        // no jQuery!
        throw new Error(resources.nojQuery);
    }

    var signalR,
        _connection,
        _pageLoaded = (window.document.readyState === "complete"),
        _pageWindow = $(window),
        _negotiateAbortText = "__Negotiate Aborted__",
        events = {
            onStart: "onStart",
            onStarting: "onStarting",
            onReceived: "onReceived",
            onError: "onError",
            onConnectionSlow: "onConnectionSlow",
            onReconnecting: "onReconnecting",
            onReconnect: "onReconnect",
            onStateChanged: "onStateChanged",
            onDisconnect: "onDisconnect"
        },
        ajaxDefaults = {
            processData: true,
            timeout: null,
            async: true,
            global: false,
            cache: false
        },
        log = function (msg, logging) {
            if (logging === false) {
                return;
            }
            var m;
            if (typeof (window.console) === "undefined") {
                return;
            }
            m = "[" + new Date().toTimeString() + "] SignalR: " + msg;
            if (window.console.debug) {
                window.console.debug(m);
            } else if (window.console.log) {
                window.console.log(m);
            }
        },

        changeState = function (connection, expectedState, newState) {
            if (expectedState === connection.state) {
                connection.state = newState;

                $(connection).triggerHandler(events.onStateChanged, [{ oldState: expectedState, newState: newState }]);
                return true;
            }

            return false;
        },

        isDisconnecting = function (connection) {
            return connection.state === signalR.connectionState.disconnected;
        },

        supportsKeepAlive = function (connection) {
            return connection._.keepAliveData.activated &&
                   connection.transport.supportsKeepAlive(connection);
        },

        configureStopReconnectingTimeout = function (connection) {
            var stopReconnectingTimeout,
                onReconnectTimeout;

            // Check if this connection has already been configured to stop reconnecting after a specified timeout.
            // Without this check if a connection is stopped then started events will be bound multiple times.
            if (!connection._.configuredStopReconnectingTimeout) {
                onReconnectTimeout = function (connection) {
                    var message = signalR._.format(signalR.resources.reconnectTimeout, connection.disconnectTimeout);
                    connection.log(message);
                    $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]);
                    connection.stop(/* async */ false, /* notifyServer */ false);
                };

                connection.reconnecting(function () {
                    var connection = this;

                    // Guard against state changing in a previous user defined even handler
                    if (connection.state === signalR.connectionState.reconnecting) {
                        stopReconnectingTimeout = window.setTimeout(function () { onReconnectTimeout(connection); }, connection.disconnectTimeout);
                    }
                });

                connection.stateChanged(function (data) {
                    if (data.oldState === signalR.connectionState.reconnecting) {
                        // Clear the pending reconnect timeout check
                        window.clearTimeout(stopReconnectingTimeout);
                    }
                });

                connection._.configuredStopReconnectingTimeout = true;
            }
        };

    signalR = function (url, qs, logging) {
        /// <summary>Creates a new SignalR connection for the given url</summary>
        /// <param name="url" type="String">The URL of the long polling endpoint</param>
        /// <param name="qs" type="Object">
        ///     [Optional] Custom querystring parameters to add to the connection URL.
        ///     If an object, every non-function member will be added to the querystring.
        ///     If a string, it's added to the QS as specified.
        /// </param>
        /// <param name="logging" type="Boolean">
        ///     [Optional] A flag indicating whether connection logging is enabled to the browser
        ///     console/log. Defaults to false.
        /// </param>

        return new signalR.fn.init(url, qs, logging);
    };

    signalR._ = {
        defaultContentType: "application/x-www-form-urlencoded; charset=UTF-8",

        ieVersion: (function () {
            var version,
                matches;

            if (window.navigator.appName === 'Microsoft Internet Explorer') {
                // Check if the user agent has the pattern "MSIE (one or more numbers).(one or more numbers)";
                matches = /MSIE ([0-9]+\.[0-9]+)/.exec(window.navigator.userAgent);

                if (matches) {
                    version = window.parseFloat(matches[1]);
                }
            }

            // undefined value means not IE
            return version;
        })(),

        error: function (message, source, context) {
            var e = new Error(message);
            e.source = source;

            if (typeof context !== "undefined") {
                e.context = context;
            }

            return e;
        },

        transportError: function (message, transport, source, context) {
            var e = this.error(message, source, context);
            e.transport = transport ? transport.name : undefined;
            return e;
        },

        format: function () {
            /// <summary>Usage: format("Hi {0}, you are {1}!", "Foo", 100) </summary>
            var s = arguments[0];
            for (var i = 0; i < arguments.length - 1; i++) {
                s = s.replace("{" + i + "}", arguments[i + 1]);
            }
            return s;
        },

        firefoxMajorVersion: function (userAgent) {
            // Firefox user agents: http://useragentstring.com/pages/Firefox/
            var matches = userAgent.match(/Firefox\/(\d+)/);
            if (!matches || !matches.length || matches.length < 2) {
                return 0;
            }
            return parseInt(matches[1], 10 /* radix */);
        },

        configurePingInterval: function (connection) {
            var config = connection._.config,
                onFail = function (error) {
                    $(connection).triggerHandler(events.onError, [error]);
                };

            if (config && !connection._.pingIntervalId && config.pingInterval) {
                connection._.pingIntervalId = window.setInterval(function () {
                    signalR.transports._logic.pingServer(connection).fail(onFail);
                }, config.pingInterval);
            }
        }
    };

    signalR.events = events;

    signalR.resources = resources;

    signalR.ajaxDefaults = ajaxDefaults;

    signalR.changeState = changeState;

    signalR.isDisconnecting = isDisconnecting;

    signalR.connectionState = {
        connecting: 0,
        connected: 1,
        reconnecting: 2,
        disconnected: 4
    };

    signalR.hub = {
        start: function () {
            // This will get replaced with the real hub connection start method when hubs is referenced correctly
            throw new Error("SignalR: Error loading hubs. Ensure your hubs reference is correct, e.g. <script src='/signalr/js'></script>.");
        }
    };

    _pageWindow.load(function () { _pageLoaded = true; });

    function validateTransport(requestedTransport, connection) {
        /// <summary>Validates the requested transport by cross checking it with the pre-defined signalR.transports</summary>
        /// <param name="requestedTransport" type="Object">The designated transports that the user has specified.</param>
        /// <param name="connection" type="signalR">The connection that will be using the requested transports.  Used for logging purposes.</param>
        /// <returns type="Object" />

        if ($.isArray(requestedTransport)) {
            // Go through transport array and remove an "invalid" tranports
            for (var i = requestedTransport.length - 1; i >= 0; i--) {
                var transport = requestedTransport[i];
                if ($.type(transport) !== "string" || !signalR.transports[transport]) {
                    connection.log("Invalid transport: " + transport + ", removing it from the transports list.");
                    requestedTransport.splice(i, 1);
                }
            }

            // Verify we still have transports left, if we dont then we have invalid transports
            if (requestedTransport.length === 0) {
                connection.log("No transports remain within the specified transport array.");
                requestedTransport = null;
            }
        } else if (!signalR.transports[requestedTransport] && requestedTransport !== "auto") {
            connection.log("Invalid transport: " + requestedTransport.toString() + ".");
            requestedTransport = null;
        } else if (requestedTransport === "auto" && signalR._.ieVersion <= 8) {
            // If we're doing an auto transport and we're IE8 then force longPolling, #1764
            return ["longPolling"];

        }

        return requestedTransport;
    }

    function getDefaultPort(protocol) {
        if (protocol === "http:") {
            return 80;
        } else if (protocol === "https:") {
            return 443;
        }
    }

    function addDefaultPort(protocol, url) {
        // Remove ports  from url.  We have to check if there's a / or end of line
        // following the port in order to avoid removing ports such as 8080.
        if (url.match(/:\d+$/)) {
            return url;
        } else {
            return url + ":" + getDefaultPort(protocol);
        }
    }

    function ConnectingMessageBuffer(connection, drainCallback) {
        var that = this,
            buffer = [];

        that.tryBuffer = function (message) {
            if (connection.state === $.signalR.connectionState.connecting) {
                buffer.push(message);

                return true;
            }

            return false;
        };

        that.drain = function () {
            // Ensure that the connection is connected when we drain (do not want to drain while a connection is not active)
            if (connection.state === $.signalR.connectionState.connected) {
                while (buffer.length > 0) {
                    drainCallback(buffer.shift());
                }
            }
        };

        that.clear = function () {
            buffer = [];
        };
    }

    signalR.fn = signalR.prototype = {
        init: function (url, qs, logging) {
            var $connection = $(this);

            this.url = url;
            this.qs = qs;
            this.lastError = null;
            this._ = {
                keepAliveData: {},
                connectingMessageBuffer: new ConnectingMessageBuffer(this, function (message) {
                    $connection.triggerHandler(events.onReceived, [message]);
                }),
                lastMessageAt: new Date().getTime(),
                lastActiveAt: new Date().getTime(),
                beatInterval: 5000, // Default value, will only be overridden if keep alive is enabled,
                beatHandle: null,
                totalTransportConnectTimeout: 0 // This will be the sum of the TransportConnectTimeout sent in response to negotiate and connection.transportConnectTimeout
            };
            if (typeof (logging) === "boolean") {
                this.logging = logging;
            }
        },

        _parseResponse: function (response) {
            var that = this;

            if (!response) {
                return response;
            } else if (typeof response === "string") {
                return that.json.parse(response);
            } else {
                return response;
            }
        },

        _originalJson: window.JSON,

        json: window.JSON,

        isCrossDomain: function (url, against) {
            /// <summary>Checks if url is cross domain</summary>
            /// <param name="url" type="String">The base URL</param>
            /// <param name="against" type="Object">
            ///     An optional argument to compare the URL against, if not specified it will be set to window.location.
            ///     If specified it must contain a protocol and a host property.
            /// </param>
            var link;

            url = $.trim(url);

            against = against || window.location;

            if (url.indexOf("http") !== 0) {
                return false;
            }

            // Create an anchor tag.
            link = window.document.createElement("a");
            link.href = url;

            // When checking for cross domain we have to special case port 80 because the window.location will remove the 
            return link.protocol + addDefaultPort(link.protocol, link.host) !== against.protocol + addDefaultPort(against.protocol, against.host);
        },

        ajaxDataType: "text",

        contentType: "application/json; charset=UTF-8",

        logging: false,

        state: signalR.connectionState.disconnected,

        clientProtocol: "1.5",

        reconnectDelay: 2000,

        transportConnectTimeout: 0,

        disconnectTimeout: 30000, // This should be set by the server in response to the negotiate request (30s default)

        reconnectWindow: 30000, // This should be set by the server in response to the negotiate request 

        keepAliveWarnAt: 2 / 3, // Warn user of slow connection if we breach the X% mark of the keep alive timeout

        start: function (options, callback) {
            /// <summary>Starts the connection</summary>
            /// <param name="options" type="Object">Options map</param>
            /// <param name="callback" type="Function">A callback function to execute when the connection has started</param>
            var connection = this,
                config = {
                    pingInterval: 300000,
                    waitForPageLoad: true,
                    transport: "auto",
                    jsonp: false
                },
                initialize,
                deferred = connection._deferral || $.Deferred(), // Check to see if there is a pre-existing deferral that's being built on, if so we want to keep using it
                parser = window.document.createElement("a");

            connection.lastError = null;

            // Persist the deferral so that if start is called multiple times the same deferral is used.
            connection._deferral = deferred;

            if (!connection.json) {
                // no JSON!
                throw new Error("SignalR: No JSON parser found. Please ensure json2.js is referenced before the SignalR.js file if you need to support clients without native JSON parsing support, e.g. IE<8.");
            }

            if ($.type(options) === "function") {
                // Support calling with single callback parameter
                callback = options;
            } else if ($.type(options) === "object") {
                $.extend(config, options);
                if ($.type(config.callback) === "function") {
                    callback = config.callback;
                }
            }

            config.transport = validateTransport(config.transport, connection);

            // If the transport is invalid throw an error and abort start
            if (!config.transport) {
                throw new Error("SignalR: Invalid transport(s) specified, aborting start.");
            }

            connection._.config = config;

            // Check to see if start is being called prior to page load
            // If waitForPageLoad is true we then want to re-direct function call to the window load event
            if (!_pageLoaded && config.waitForPageLoad === true) {
                connection._.deferredStartHandler = function () {
                    connection.start(options, callback);
                };
                _pageWindow.bind("load", connection._.deferredStartHandler);

                return deferred.promise();
            }

            // If we're already connecting just return the same deferral as the original connection start
            if (connection.state === signalR.connectionState.connecting) {
                return deferred.promise();
            } else if (changeState(connection,
                            signalR.connectionState.disconnected,
                            signalR.connectionState.connecting) === false) {
                // We're not connecting so try and transition into connecting.
                // If we fail to transition then we're either in connected or reconnecting.

                deferred.resolve(connection);
                return deferred.promise();
            }

            configureStopReconnectingTimeout(connection);

            // Resolve the full url
            parser.href = connection.url;
            if (!parser.protocol || parser.protocol === ":") {
                connection.protocol = window.document.location.protocol;
                connection.host = parser.host || window.document.location.host;
            } else {
                connection.protocol = parser.protocol;
                connection.host = parser.host;
            }

            connection.baseUrl = connection.protocol + "//" + connection.host;

            // Set the websocket protocol
            connection.wsProtocol = connection.protocol === "https:" ? "wss://" : "ws://";

            // If jsonp with no/auto transport is specified, then set the transport to long polling
            // since that is the only transport for which jsonp really makes sense.
            // Some developers might actually choose to specify jsonp for same origin requests
            // as demonstrated by Issue #623.
            if (config.transport === "auto" && config.jsonp === true) {
                config.transport = "longPolling";
            }

            // If the url is protocol relative, prepend the current windows protocol to the url. 
            if (connection.url.indexOf("//") === 0) {
                connection.url = window.location.protocol + connection.url;
                connection.log("Protocol relative URL detected, normalizing it to '" + connection.url + "'.");
            }

            if (this.isCrossDomain(connection.url)) {
                connection.log("Auto detected cross domain url.");

                if (config.transport === "auto") {
                    // TODO: Support XDM with foreverFrame
                    config.transport = ["webSockets", "serverSentEvents", "longPolling"];
                }

                if (typeof (config.withCredentials) === "undefined") {
                    config.withCredentials = true;
                }

                // Determine if jsonp is the only choice for negotiation, ajaxSend and ajaxAbort.
                // i.e. if the browser doesn't supports CORS
                // If it is, ignore any preference to the contrary, and switch to jsonp.
                if (!config.jsonp) {
                    config.jsonp = !$.support.cors;

                    if (config.jsonp) {
                        connection.log("Using jsonp because this browser doesn't support CORS.");
                    }
                }

                connection.contentType = signalR._.defaultContentType;
            }

            connection.withCredentials = config.withCredentials;

            connection.ajaxDataType = config.jsonp ? "jsonp" : "text";

            $(connection).bind(events.onStart, function (e, data) {
                if ($.type(callback) === "function") {
                    callback.call(connection);
                }
                deferred.resolve(connection);
            });

            connection._.initHandler = signalR.transports._logic.initHandler(connection);

            initialize = function (transports, index) {
                var noTransportError = signalR._.error(resources.noTransportOnInit);

                index = index || 0;
                if (index >= transports.length) {
                    if (index === 0) {
                        connection.log("No transports supported by the server were selected.");
                    } else if (index === 1) {
                        connection.log("No fallback transports were selected.");
                    } else {
                        connection.log("Fallback transports exhausted.");
                    }

                    // No transport initialized successfully
                    $(connection).triggerHandler(events.onError, [noTransportError]);
                    deferred.reject(noTransportError);
                    // Stop the connection if it has connected and move it into the disconnected state
                    connection.stop();
                    return;
                }

                // The connection was aborted
                if (connection.state === signalR.connectionState.disconnected) {
                    return;
                }

                var transportName = transports[index],
                    transport = signalR.transports[transportName],
                    onFallback = function () {
                        initialize(transports, index + 1);
                    };

                connection.transport = transport;

                try {
                    connection._.initHandler.start(transport, function () { // success
                        // Firefox 11+ doesn't allow sync XHR withCredentials: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#withCredentials
                        var isFirefox11OrGreater = signalR._.firefoxMajorVersion(window.navigator.userAgent) >= 11,
                            asyncAbort = !!connection.withCredentials && isFirefox11OrGreater;

                        connection.log("The start request succeeded. Transitioning to the connected state.");

                        if (supportsKeepAlive(connection)) {
                            signalR.transports._logic.monitorKeepAlive(connection);
                        }

                        signalR.transports._logic.startHeartbeat(connection);

                        // Used to ensure low activity clients maintain their authentication.
                        // Must be configured once a transport has been decided to perform valid ping requests.
                        signalR._.configurePingInterval(connection);

                        if (!changeState(connection,
                                            signalR.connectionState.connecting,
                                            signalR.connectionState.connected)) {
                            connection.log("WARNING! The connection was not in the connecting state.");
                        }

                        // Drain any incoming buffered messages (messages that came in prior to connect)
                        connection._.connectingMessageBuffer.drain();

                        $(connection).triggerHandler(events.onStart);

                        // wire the stop handler for when the user leaves the page
                        _pageWindow.bind("unload", function () {
                            connection.log("Window unloading, stopping the connection.");

                            connection.stop(asyncAbort);
                        });

                        if (isFirefox11OrGreater) {
                            // Firefox does not fire cross-domain XHRs in the normal unload handler on tab close.
                            // #2400
                            _pageWindow.bind("beforeunload", function () {
                                // If connection.stop() runs runs in beforeunload and fails, it will also fail
                                // in unload unless connection.stop() runs after a timeout.
                                window.setTimeout(function () {
                                    connection.stop(asyncAbort);
                                }, 0);
                            });
                        }
                    }, onFallback);
                }
                catch (error) {
                    connection.log(transport.name + " transport threw '" + error.message + "' when attempting to start.");
                    onFallback();
                }
            };

            var url = connection.url + "/negotiate",
                onFailed = function (error, connection) {
                    var err = signalR._.error(resources.errorOnNegotiate, error, connection._.negotiateRequest);

                    $(connection).triggerHandler(events.onError, err);
                    deferred.reject(err);
                    // Stop the connection if negotiate failed
                    connection.stop();
                };

            $(connection).triggerHandler(events.onStarting);

            url = signalR.transports._logic.prepareQueryString(connection, url);

            connection.log("Negotiating with '" + url + "'.");

            // Save the ajax negotiate request object so we can abort it if stop is called while the request is in flight.
            connection._.negotiateRequest = signalR.transports._logic.ajax(connection, {
                url: url,
                error: function (error, statusText) {
                    // We don't want to cause any errors if we're aborting our own negotiate request.
                    if (statusText !== _negotiateAbortText) {
                        onFailed(error, connection);
                    } else {
                        // This rejection will noop if the deferred has already been resolved or rejected.
                        deferred.reject(signalR._.error(resources.stoppedWhileNegotiating, null /* error */, connection._.negotiateRequest));
                    }
                },
                success: function (result) {
                    var res,
                        keepAliveData,
                        protocolError,
                        transports = [],
                        supportedTransports = [];

                    try {
                        res = connection._parseResponse(result);
                    } catch (error) {
                        onFailed(signalR._.error(resources.errorParsingNegotiateResponse, error), connection);
                        return;
                    }

                    keepAliveData = connection._.keepAliveData;
                    connection.appRelativeUrl = res.Url;
                    connection.id = res.ConnectionId;
                    connection.token = res.ConnectionToken;
                    connection.webSocketServerUrl = res.WebSocketServerUrl;

                    // The long poll timeout is the ConnectionTimeout plus 10 seconds
                    connection._.pollTimeout = res.ConnectionTimeout * 1000 + 10000; // in ms

                    // Once the server has labeled the PersistentConnection as Disconnected, we should stop attempting to reconnect
                    // after res.DisconnectTimeout seconds.
                    connection.disconnectTimeout = res.DisconnectTimeout * 1000; // in ms

                    // Add the TransportConnectTimeout from the response to the transportConnectTimeout from the client to calculate the total timeout
                    connection._.totalTransportConnectTimeout = connection.transportConnectTimeout + res.TransportConnectTimeout * 1000;

                    // If we have a keep alive
                    if (res.KeepAliveTimeout) {
                        // Register the keep alive data as activated
                        keepAliveData.activated = true;

                        // Timeout to designate when to force the connection into reconnecting converted to milliseconds
                        keepAliveData.timeout = res.KeepAliveTimeout * 1000;

                        // Timeout to designate when to warn the developer that the connection may be dead or is not responding.
                        keepAliveData.timeoutWarning = keepAliveData.timeout * connection.keepAliveWarnAt;

                        // Instantiate the frequency in which we check the keep alive.  It must be short in order to not miss/pick up any changes
                        connection._.beatInterval = (keepAliveData.timeout - keepAliveData.timeoutWarning) / 3;
                    } else {
                        keepAliveData.activated = false;
                    }

                    connection.reconnectWindow = connection.disconnectTimeout + (keepAliveData.timeout || 0);

                    if (!res.ProtocolVersion || res.ProtocolVersion !== connection.clientProtocol) {
                        protocolError = signalR._.error(signalR._.format(resources.protocolIncompatible, connection.clientProtocol, res.ProtocolVersion));
                        $(connection).triggerHandler(events.onError, [protocolError]);
                        deferred.reject(protocolError);

                        return;
                    }

                    $.each(signalR.transports, function (key) {
                        if ((key.indexOf("_") === 0) || (key === "webSockets" && !res.TryWebSockets)) {
                            return true;
                        }
                        supportedTransports.push(key);
                    });

                    if ($.isArray(config.transport)) {
                        $.each(config.transport, function (_, transport) {
                            if ($.inArray(transport, supportedTransports) >= 0) {
                                transports.push(transport);
                            }
                        });
                    } else if (config.transport === "auto") {
                        transports = supportedTransports;
                    } else if ($.inArray(config.transport, supportedTransports) >= 0) {
                        transports.push(config.transport);
                    }

                    initialize(transports);
                }
            });

            return deferred.promise();
        },

        starting: function (callback) {
            /// <summary>Adds a callback that will be invoked before anything is sent over the connection</summary>
            /// <param name="callback" type="Function">A callback function to execute before the connection is fully instantiated.</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onStarting, function (e, data) {
                callback.call(connection);
            });
            return connection;
        },

        send: function (data) {
            /// <summary>Sends data over the connection</summary>
            /// <param name="data" type="String">The data to send over the connection</param>
            /// <returns type="signalR" />
            var connection = this;

            if (connection.state === signalR.connectionState.disconnected) {
                // Connection hasn't been started yet
                throw new Error("SignalR: Connection must be started before data can be sent. Call .start() before .send()");
            }

            if (connection.state === signalR.connectionState.connecting) {
                // Connection hasn't been started yet
                throw new Error("SignalR: Connection has not been fully initialized. Use .start().done() or .start().fail() to run logic after the connection has started.");
            }

            connection.transport.send(connection, data);
            // REVIEW: Should we return deferred here?
            return connection;
        },

        received: function (callback) {
            /// <summary>Adds a callback that will be invoked after anything is received over the connection</summary>
            /// <param name="callback" type="Function">A callback function to execute when any data is received on the connection</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onReceived, function (e, data) {
                callback.call(connection, data);
            });
            return connection;
        },

        stateChanged: function (callback) {
            /// <summary>Adds a callback that will be invoked when the connection state changes</summary>
            /// <param name="callback" type="Function">A callback function to execute when the connection state changes</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onStateChanged, function (e, data) {
                callback.call(connection, data);
            });
            return connection;
        },

        error: function (callback) {
            /// <summary>Adds a callback that will be invoked after an error occurs with the connection</summary>
            /// <param name="callback" type="Function">A callback function to execute when an error occurs on the connection</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onError, function (e, errorData, sendData) {
                connection.lastError = errorData;
                // In practice 'errorData' is the SignalR built error object.
                // In practice 'sendData' is undefined for all error events except those triggered by
                // 'ajaxSend' and 'webSockets.send'.'sendData' is the original send payload.
                callback.call(connection, errorData, sendData);
            });
            return connection;
        },

        disconnected: function (callback) {
            /// <summary>Adds a callback that will be invoked when the client disconnects</summary>
            /// <param name="callback" type="Function">A callback function to execute when the connection is broken</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onDisconnect, function (e, data) {
                callback.call(connection);
            });
            return connection;
        },

        connectionSlow: function (callback) {
            /// <summary>Adds a callback that will be invoked when the client detects a slow connection</summary>
            /// <param name="callback" type="Function">A callback function to execute when the connection is slow</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onConnectionSlow, function (e, data) {
                callback.call(connection);
            });

            return connection;
        },

        reconnecting: function (callback) {
            /// <summary>Adds a callback that will be invoked when the underlying transport begins reconnecting</summary>
            /// <param name="callback" type="Function">A callback function to execute when the connection enters a reconnecting state</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onReconnecting, function (e, data) {
                callback.call(connection);
            });
            return connection;
        },

        reconnected: function (callback) {
            /// <summary>Adds a callback that will be invoked when the underlying transport reconnects</summary>
            /// <param name="callback" type="Function">A callback function to execute when the connection is restored</param>
            /// <returns type="signalR" />
            var connection = this;
            $(connection).bind(events.onReconnect, function (e, data) {
                callback.call(connection);
            });
            return connection;
        },

        stop: function (async, notifyServer) {
            /// <summary>Stops listening</summary>
            /// <param name="async" type="Boolean">Whether or not to asynchronously abort the connection</param>
            /// <param name="notifyServer" type="Boolean">Whether we want to notify the server that we are aborting the connection</param>
            /// <returns type="signalR" />
            var connection = this,
                // Save deferral because this is always cleaned up
                deferral = connection._deferral;

            // Verify that we've bound a load event.
            if (connection._.deferredStartHandler) {
                // Unbind the event.
                _pageWindow.unbind("load", connection._.deferredStartHandler);
            }

            // Always clean up private non-timeout based state.
            delete connection._.config;
            delete connection._.deferredStartHandler;

            // This needs to be checked despite the connection state because a connection start can be deferred until page load.
            // If we've deferred the start due to a page load we need to unbind the "onLoad" -> start event.
            if (!_pageLoaded && (!connection._.config || connection._.config.waitForPageLoad === true)) {
                connection.log("Stopping connection prior to negotiate.");

                // If we have a deferral we should reject it
                if (deferral) {
                    deferral.reject(signalR._.error(resources.stoppedWhileLoading));
                }

                // Short-circuit because the start has not been fully started.
                return;
            }

            if (connection.state === signalR.connectionState.disconnected) {
                return;
            }

            connection.log("Stopping connection.");

            changeState(connection, connection.state, signalR.connectionState.disconnected);

            // Clear this no matter what
            window.clearTimeout(connection._.beatHandle);
            window.clearInterval(connection._.pingIntervalId);

            if (connection.transport) {
                connection.transport.stop(connection);

                if (notifyServer !== false) {
                    connection.transport.abort(connection, async);
                }

                if (supportsKeepAlive(connection)) {
                    signalR.transports._logic.stopMonitoringKeepAlive(connection);
                }

                connection.transport = null;
            }

            if (connection._.negotiateRequest) {
                // If the negotiation request has already completed this will noop.
                connection._.negotiateRequest.abort(_negotiateAbortText);
                delete connection._.negotiateRequest;
            }

            // Ensure that initHandler.stop() is called before connection._deferral is deleted
            if (connection._.initHandler) {
                connection._.initHandler.stop();
            }

            // Trigger the disconnect event
            $(connection).triggerHandler(events.onDisconnect);

            delete connection._deferral;
            delete connection.messageId;
            delete connection.groupsToken;
            delete connection.id;
            delete connection._.pingIntervalId;
            delete connection._.lastMessageAt;
            delete connection._.lastActiveAt;

            // Clear out our message buffer
            connection._.connectingMessageBuffer.clear();

            return connection;
        },

        log: function (msg) {
            log(msg, this.logging);
        }
    };

    signalR.fn.init.prototype = signalR.fn;

    signalR.noConflict = function () {
        /// <summary>Reinstates the original value of $.connection and returns the signalR object for manual assignment</summary>
        /// <returns type="signalR" />
        if ($.connection === signalR) {
            $.connection = _connection;
        }
        return signalR;
    };

    if ($.connection) {
        _connection = $.connection;
    }

    $.connection = $.signalR = signalR;

}(window.jQuery, window));
/* jquery.signalR.transports.common.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.core.js" />

(function ($, window, undefined) {

    var signalR = $.signalR,
        events = $.signalR.events,
        changeState = $.signalR.changeState,
        startAbortText = "__Start Aborted__",
        transportLogic;

    signalR.transports = {};

    function beat(connection) {
        if (connection._.keepAliveData.monitoring) {
            checkIfAlive(connection);
        }

        // Ensure that we successfully marked active before continuing the heartbeat.
        if (transportLogic.markActive(connection)) {
            connection._.beatHandle = window.setTimeout(function () {
                beat(connection);
            }, connection._.beatInterval);
        }
    }

    function checkIfAlive(connection) {
        var keepAliveData = connection._.keepAliveData,
            timeElapsed;

        // Only check if we're connected
        if (connection.state === signalR.connectionState.connected) {
            timeElapsed = new Date().getTime() - connection._.lastMessageAt;

            // Check if the keep alive has completely timed out
            if (timeElapsed >= keepAliveData.timeout) {
                connection.log("Keep alive timed out.  Notifying transport that connection has been lost.");

                // Notify transport that the connection has been lost
                connection.transport.lostConnection(connection);
            } else if (timeElapsed >= keepAliveData.timeoutWarning) {
                // This is to assure that the user only gets a single warning
                if (!keepAliveData.userNotified) {
                    connection.log("Keep alive has been missed, connection may be dead/slow.");
                    $(connection).triggerHandler(events.onConnectionSlow);
                    keepAliveData.userNotified = true;
                }
            } else {
                keepAliveData.userNotified = false;
            }
        }
    }

    function getAjaxUrl(connection, path) {
        var url = connection.url + path;

        if (connection.transport) {
            url += "?transport=" + connection.transport.name;
        }

        return transportLogic.prepareQueryString(connection, url);
    }

    function InitHandler(connection) {
        this.connection = connection;

        this.startRequested = false;
        this.startCompleted = false;
        this.connectionStopped = false;
    }

    InitHandler.prototype = {
        start: function (transport, onSuccess, onFallback) {
            var that = this,
                connection = that.connection,
                failCalled = false;

            if (that.startRequested || that.connectionStopped) {
                connection.log("WARNING! " + transport.name + " transport cannot be started. Initialization ongoing or completed.");
                return;
            }

            connection.log(transport.name + " transport starting.");

            that.transportTimeoutHandle = window.setTimeout(function () {
                if (!failCalled) {
                    failCalled = true;
                    connection.log(transport.name + " transport timed out when trying to connect.");
                    that.transportFailed(transport, undefined, onFallback);
                }
            }, connection._.totalTransportConnectTimeout);

            transport.start(connection, function () {
                if (!failCalled) {
                    that.initReceived(transport, onSuccess);
                }
            }, function (error) {
                // Don't allow the same transport to cause onFallback to be called twice
                if (!failCalled) {
                    failCalled = true;
                    that.transportFailed(transport, error, onFallback);
                }

                // Returns true if the transport should stop;
                // false if it should attempt to reconnect
                return !that.startCompleted || that.connectionStopped;
            });
        },

        stop: function () {
            this.connectionStopped = true;
            window.clearTimeout(this.transportTimeoutHandle);
            signalR.transports._logic.tryAbortStartRequest(this.connection);
        },

        initReceived: function (transport, onSuccess) {
            var that = this,
                connection = that.connection;

            if (that.startRequested) {
                connection.log("WARNING! The client received multiple init messages.");
                return;
            }

            if (that.connectionStopped) {
                return;
            }

            that.startRequested = true;
            window.clearTimeout(that.transportTimeoutHandle);

            connection.log(transport.name + " transport connected. Initiating start request.");
            signalR.transports._logic.ajaxStart(connection, function () {
                that.startCompleted = true;
                onSuccess();
            });
        },

        transportFailed: function (transport, error, onFallback) {
            var connection = this.connection,
                deferred = connection._deferral,
                wrappedError;

            if (this.connectionStopped) {
                return;
            }

            window.clearTimeout(this.transportTimeoutHandle);

            if (!this.startRequested) {
                transport.stop(connection);

                connection.log(transport.name + " transport failed to connect. Attempting to fall back.");
                onFallback();
            } else if (!this.startCompleted) {
                // Do not attempt to fall back if a start request is ongoing during a transport failure.
                // Instead, trigger an error and stop the connection.
                wrappedError = signalR._.error(signalR.resources.errorDuringStartRequest, error);

                connection.log(transport.name + " transport failed during the start request. Stopping the connection.");
                $(connection).triggerHandler(events.onError, [wrappedError]);
                if (deferred) {
                    deferred.reject(wrappedError);
                }

                connection.stop();
            } else {
                // The start request has completed, but the connection has not stopped.
                // No need to do anything here. The transport should attempt its normal reconnect logic.
            }
        }
    };

    transportLogic = signalR.transports._logic = {
        ajax: function (connection, options) {
            return $.ajax(
                $.extend(/*deep copy*/ true, {}, $.signalR.ajaxDefaults, {
                    type: "GET",
                    data: {},
                    xhrFields: { withCredentials: connection.withCredentials },
                    contentType: connection.contentType,
                    dataType: connection.ajaxDataType
                }, options));
        },

        pingServer: function (connection) {
            /// <summary>Pings the server</summary>
            /// <param name="connection" type="signalr">Connection associated with the server ping</param>
            /// <returns type="signalR" />
            var url,
                xhr,
                deferral = $.Deferred();

            if (connection.transport) {
                url = connection.url + "/ping";

                url = transportLogic.addQs(url, connection.qs);

                xhr = transportLogic.ajax(connection, {
                    url: url,
                    success: function (result) {
                        var data;

                        try {
                            data = connection._parseResponse(result);
                        }
                        catch (error) {
                            deferral.reject(
                                signalR._.transportError(
                                    signalR.resources.pingServerFailedParse,
                                    connection.transport,
                                    error,
                                    xhr
                                )
                            );
                            connection.stop();
                            return;
                        }

                        if (data.Response === "pong") {
                            deferral.resolve();
                        }
                        else {
                            deferral.reject(
                                signalR._.transportError(
                                    signalR._.format(signalR.resources.pingServerFailedInvalidResponse, result),
                                    connection.transport,
                                    null /* error */,
                                    xhr
                                )
                            );
                        }
                    },
                    error: function (error) {
                        if (error.status === 401 || error.status === 403) {
                            deferral.reject(
                                signalR._.transportError(
                                    signalR._.format(signalR.resources.pingServerFailedStatusCode, error.status),
                                    connection.transport,
                                    error,
                                    xhr
                                )
                            );
                            connection.stop();
                        }
                        else {
                            deferral.reject(
                                signalR._.transportError(
                                    signalR.resources.pingServerFailed,
                                    connection.transport,
                                    error,
                                    xhr
                                )
                            );
                        }
                    }
                });
            }
            else {
                deferral.reject(
                    signalR._.transportError(
                        signalR.resources.noConnectionTransport,
                        connection.transport
                    )
                );
            }

            return deferral.promise();
        },

        prepareQueryString: function (connection, url) {
            var preparedUrl;

            // Use addQs to start since it handles the ?/& prefix for us
            preparedUrl = transportLogic.addQs(url, "clientProtocol=" + connection.clientProtocol);

            // Add the user-specified query string params if any
            preparedUrl = transportLogic.addQs(preparedUrl, connection.qs);

            if (connection.token) {
                preparedUrl += "&connectionToken=" + window.encodeURIComponent(connection.token);
            }

            if (connection.data) {
                preparedUrl += "&connectionData=" + window.encodeURIComponent(connection.data);
            }

            return preparedUrl;
        },

        addQs: function (url, qs) {
            var appender = url.indexOf("?") !== -1 ? "&" : "?",
                firstChar;

            if (!qs) {
                return url;
            }

            if (typeof (qs) === "object") {
                return url + appender + $.param(qs);
            }

            if (typeof (qs) === "string") {
                firstChar = qs.charAt(0);

                if (firstChar === "?" || firstChar === "&") {
                    appender = "";
                }

                return url + appender + qs;
            }

            throw new Error("Query string property must be either a string or object.");
        },

        // BUG #2953: The url needs to be same otherwise it will cause a memory leak
        getUrl: function (connection, transport, reconnecting, poll, ajaxPost) {
            /// <summary>Gets the url for making a GET based connect request</summary>
            var baseUrl = transport === "webSockets" ? "" : connection.baseUrl,
                url = baseUrl + connection.appRelativeUrl,
                qs = "transport=" + transport;

            if (!ajaxPost && connection.groupsToken) {
                qs += "&groupsToken=" + window.encodeURIComponent(connection.groupsToken);
            }

            if (!reconnecting) {
                url += "/connect";
            } else {
                if (poll) {
                    // longPolling transport specific
                    url += "/poll";
                } else {
                    url += "/reconnect";
                }

                if (!ajaxPost && connection.messageId) {
                    qs += "&messageId=" + window.encodeURIComponent(connection.messageId);
                }
            }
            url += "?" + qs;
            url = transportLogic.prepareQueryString(connection, url);

            if (!ajaxPost) {
                url += "&tid=" + Math.floor(Math.random() * 11);
            }

            return url;
        },

        maximizePersistentResponse: function (minPersistentResponse) {
            return {
                MessageId: minPersistentResponse.C,
                Messages: minPersistentResponse.M,
                Initialized: typeof (minPersistentResponse.S) !== "undefined" ? true : false,
                ShouldReconnect: typeof (minPersistentResponse.T) !== "undefined" ? true : false,
                LongPollDelay: minPersistentResponse.L,
                GroupsToken: minPersistentResponse.G
            };
        },

        updateGroups: function (connection, groupsToken) {
            if (groupsToken) {
                connection.groupsToken = groupsToken;
            }
        },

        stringifySend: function (connection, message) {
            if (typeof (message) === "string" || typeof (message) === "undefined" || message === null) {
                return message;
            }
            return connection.json.stringify(message);
        },

        ajaxSend: function (connection, data) {
            var payload = transportLogic.stringifySend(connection, data),
                url = getAjaxUrl(connection, "/send"),
                xhr,
                onFail = function (error, connection) {
                    $(connection).triggerHandler(events.onError, [signalR._.transportError(signalR.resources.sendFailed, connection.transport, error, xhr), data]);
                };


            xhr = transportLogic.ajax(connection, {
                url: url,
                type: connection.ajaxDataType === "jsonp" ? "GET" : "POST",
                contentType: signalR._.defaultContentType,
                data: {
                    data: payload
                },
                success: function (result) {
                    var res;

                    if (result) {
                        try {
                            res = connection._parseResponse(result);
                        }
                        catch (error) {
                            onFail(error, connection);
                            connection.stop();
                            return;
                        }

                        transportLogic.triggerReceived(connection, res);
                    }
                },
                error: function (error, textStatus) {
                    if (textStatus === "abort" || textStatus === "parsererror") {
                        // The parsererror happens for sends that don't return any data, and hence
                        // don't write the jsonp callback to the response. This is harder to fix on the server
                        // so just hack around it on the client for now.
                        return;
                    }

                    onFail(error, connection);
                }
            });

            return xhr;
        },

        ajaxAbort: function (connection, async) {
            if (typeof (connection.transport) === "undefined") {
                return;
            }

            // Async by default unless explicitly overidden
            async = typeof async === "undefined" ? true : async;

            var url = getAjaxUrl(connection, "/abort");

            transportLogic.ajax(connection, {
                url: url,
                async: async,
                timeout: 1000,
                type: "POST"
            });

            connection.log("Fired ajax abort async = " + async + ".");
        },

        ajaxStart: function (connection, onSuccess) {
            var rejectDeferred = function (error) {
                    var deferred = connection._deferral;
                    if (deferred) {
                        deferred.reject(error);
                    }
                },
                triggerStartError = function (error) {
                    connection.log("The start request failed. Stopping the connection.");
                    $(connection).triggerHandler(events.onError, [error]);
                    rejectDeferred(error);
                    connection.stop();
                };

            connection._.startRequest = transportLogic.ajax(connection, {
                url: getAjaxUrl(connection, "/start"),
                success: function (result, statusText, xhr) {
                    var data;

                    try {
                        data = connection._parseResponse(result);
                    } catch (error) {
                        triggerStartError(signalR._.error(
                            signalR._.format(signalR.resources.errorParsingStartResponse, result),
                            error, xhr));
                        return;
                    }

                    if (data.Response === "started") {
                        onSuccess();
                    } else {
                        triggerStartError(signalR._.error(
                            signalR._.format(signalR.resources.invalidStartResponse, result),
                            null /* error */, xhr));
                    }
                },
                error: function (xhr, statusText, error) {
                    if (statusText !== startAbortText) {
                        triggerStartError(signalR._.error(
                            signalR.resources.errorDuringStartRequest,
                            error, xhr));
                    } else {
                        // Stop has been called, no need to trigger the error handler
                        // or stop the connection again with onStartError
                        connection.log("The start request aborted because connection.stop() was called.");
                        rejectDeferred(signalR._.error(
                            signalR.resources.stoppedDuringStartRequest,
                            null /* error */, xhr));
                    }
                }
            });
        },

        tryAbortStartRequest: function (connection) {
            if (connection._.startRequest) {
                // If the start request has already completed this will noop.
                connection._.startRequest.abort(startAbortText);
                delete connection._.startRequest;
            }
        },

        tryInitialize: function (persistentResponse, onInitialized) {
            if (persistentResponse.Initialized) {
                onInitialized();
            }
        },

        triggerReceived: function (connection, data) {
            if (!connection._.connectingMessageBuffer.tryBuffer(data)) {
                $(connection).triggerHandler(events.onReceived, [data]);
            }
        },

        processMessages: function (connection, minData, onInitialized) {
            var data;

            // Update the last message time stamp
            transportLogic.markLastMessage(connection);

            if (minData) {
                data = transportLogic.maximizePersistentResponse(minData);

                transportLogic.updateGroups(connection, data.GroupsToken);

                if (data.MessageId) {
                    connection.messageId = data.MessageId;
                }

                if (data.Messages) {
                    $.each(data.Messages, function (index, message) {
                        transportLogic.triggerReceived(connection, message);
                    });

                    transportLogic.tryInitialize(data, onInitialized);
                }
            }
        },

        monitorKeepAlive: function (connection) {
            var keepAliveData = connection._.keepAliveData;

            // If we haven't initiated the keep alive timeouts then we need to
            if (!keepAliveData.monitoring) {
                keepAliveData.monitoring = true;

                transportLogic.markLastMessage(connection);

                // Save the function so we can unbind it on stop
                connection._.keepAliveData.reconnectKeepAliveUpdate = function () {
                    // Mark a new message so that keep alive doesn't time out connections
                    transportLogic.markLastMessage(connection);
                };

                // Update Keep alive on reconnect
                $(connection).bind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate);

                connection.log("Now monitoring keep alive with a warning timeout of " + keepAliveData.timeoutWarning + ", keep alive timeout of " + keepAliveData.timeout + " and disconnecting timeout of " + connection.disconnectTimeout);
            } else {
                connection.log("Tried to monitor keep alive but it's already being monitored.");
            }
        },

        stopMonitoringKeepAlive: function (connection) {
            var keepAliveData = connection._.keepAliveData;

            // Only attempt to stop the keep alive monitoring if its being monitored
            if (keepAliveData.monitoring) {
                // Stop monitoring
                keepAliveData.monitoring = false;

                // Remove the updateKeepAlive function from the reconnect event
                $(connection).unbind(events.onReconnect, connection._.keepAliveData.reconnectKeepAliveUpdate);

                // Clear all the keep alive data
                connection._.keepAliveData = {};
                connection.log("Stopping the monitoring of the keep alive.");
            }
        },

        startHeartbeat: function (connection) {
            connection._.lastActiveAt = new Date().getTime();
            beat(connection);
        },

        markLastMessage: function (connection) {
            connection._.lastMessageAt = new Date().getTime();
        },

        markActive: function (connection) {
            if (transportLogic.verifyLastActive(connection)) {
                connection._.lastActiveAt = new Date().getTime();
                return true;
            }

            return false;
        },

        isConnectedOrReconnecting: function (connection) {
            return connection.state === signalR.connectionState.connected ||
                   connection.state === signalR.connectionState.reconnecting;
        },

        ensureReconnectingState: function (connection) {
            if (changeState(connection,
                        signalR.connectionState.connected,
                        signalR.connectionState.reconnecting) === true) {
                $(connection).triggerHandler(events.onReconnecting);
            }
            return connection.state === signalR.connectionState.reconnecting;
        },

        clearReconnectTimeout: function (connection) {
            if (connection && connection._.reconnectTimeout) {
                window.clearTimeout(connection._.reconnectTimeout);
                delete connection._.reconnectTimeout;
            }
        },

        verifyLastActive: function (connection) {
            if (new Date().getTime() - connection._.lastActiveAt >= connection.reconnectWindow) {
                var message = signalR._.format(signalR.resources.reconnectWindowTimeout, new Date(connection._.lastActiveAt), connection.reconnectWindow);
                connection.log(message);
                $(connection).triggerHandler(events.onError, [signalR._.error(message, /* source */ "TimeoutException")]);
                connection.stop(/* async */ false, /* notifyServer */ false);
                return false;
            }

            return true;
        },

        reconnect: function (connection, transportName) {
            var transport = signalR.transports[transportName];

            // We should only set a reconnectTimeout if we are currently connected
            // and a reconnectTimeout isn't already set.
            if (transportLogic.isConnectedOrReconnecting(connection) && !connection._.reconnectTimeout) {
                // Need to verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration.
                if (!transportLogic.verifyLastActive(connection)) {
                    return;
                }

                connection._.reconnectTimeout = window.setTimeout(function () {
                    if (!transportLogic.verifyLastActive(connection)) {
                        return;
                    }

                    transport.stop(connection);

                    if (transportLogic.ensureReconnectingState(connection)) {
                        connection.log(transportName + " reconnecting.");
                        transport.start(connection);
                    }
                }, connection.reconnectDelay);
            }
        },

        handleParseFailure: function (connection, result, error, onFailed, context) {
            var wrappedError = signalR._.transportError(
                signalR._.format(signalR.resources.parseFailed, result),
                connection.transport,
                error,
                context);

            // If we're in the initialization phase trigger onFailed, otherwise stop the connection.
            if (onFailed && onFailed(wrappedError)) {
                connection.log("Failed to parse server response while attempting to connect.");
            } else {
                $(connection).triggerHandler(events.onError, [wrappedError]);
                connection.stop();
            }
        },

        initHandler: function (connection) {
            return new InitHandler(connection);
        },

        foreverFrame: {
            count: 0,
            connections: {}
        }
    };

}(window.jQuery, window));
/* jquery.signalR.transports.webSockets.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.transports.common.js" />

(function ($, window, undefined) {

    var signalR = $.signalR,
        events = $.signalR.events,
        changeState = $.signalR.changeState,
        transportLogic = signalR.transports._logic;

    signalR.transports.webSockets = {
        name: "webSockets",

        supportsKeepAlive: function () {
            return true;
        },

        send: function (connection, data) {
            var payload = transportLogic.stringifySend(connection, data);

            try {
                connection.socket.send(payload);
            } catch (ex) {
                $(connection).triggerHandler(events.onError,
                    [signalR._.transportError(
                        signalR.resources.webSocketsInvalidState,
                        connection.transport,
                        ex,
                        connection.socket
                    ),
                    data]);
            }
        },

        start: function (connection, onSuccess, onFailed) {
            var url,
                opened = false,
                that = this,
                reconnecting = !onSuccess,
                $connection = $(connection);

            if (!window.WebSocket) {
                onFailed();
                return;
            }

            if (!connection.socket) {
                if (connection.webSocketServerUrl) {
                    url = connection.webSocketServerUrl;
                } else {
                    url = connection.wsProtocol + connection.host;
                }

                url += transportLogic.getUrl(connection, this.name, reconnecting);

                connection.log("Connecting to websocket endpoint '" + url + "'.");
                connection.socket = new window.WebSocket(url);

                connection.socket.onopen = function () {
                    opened = true;
                    connection.log("Websocket opened.");

                    transportLogic.clearReconnectTimeout(connection);

                    if (changeState(connection,
                                    signalR.connectionState.reconnecting,
                                    signalR.connectionState.connected) === true) {
                        $connection.triggerHandler(events.onReconnect);
                    }
                };

                connection.socket.onclose = function (event) {
                    var error;

                    // Only handle a socket close if the close is from the current socket.
                    // Sometimes on disconnect the server will push down an onclose event
                    // to an expired socket.

                    if (this === connection.socket) {
                        if (opened && typeof event.wasClean !== "undefined" && event.wasClean === false) {
                            // Ideally this would use the websocket.onerror handler (rather than checking wasClean in onclose) but
                            // I found in some circumstances Chrome won't call onerror. This implementation seems to work on all browsers.
                            error = signalR._.transportError(
                                signalR.resources.webSocketClosed,
                                connection.transport,
                                event);

                            connection.log("Unclean disconnect from websocket: " + (event.reason || "[no reason given]."));
                        } else {
                            connection.log("Websocket closed.");
                        }

                        if (!onFailed || !onFailed(error)) {
                            if (error) {
                                $(connection).triggerHandler(events.onError, [error]);
                            }

                            that.reconnect(connection);
                        }
                    }
                };

                connection.socket.onmessage = function (event) {
                    var data;

                    try {
                        data = connection._parseResponse(event.data);
                    }
                    catch (error) {
                        transportLogic.handleParseFailure(connection, event.data, error, onFailed, event);
                        return;
                    }

                    if (data) {
                        // data.M is PersistentResponse.Messages
                        if ($.isEmptyObject(data) || data.M) {
                            transportLogic.processMessages(connection, data, onSuccess);
                        } else {
                            // For websockets we need to trigger onReceived
                            // for callbacks to outgoing hub calls.
                            transportLogic.triggerReceived(connection, data);
                        }
                    }
                };
            }
        },

        reconnect: function (connection) {
            transportLogic.reconnect(connection, this.name);
        },

        lostConnection: function (connection) {
            this.reconnect(connection);
        },

        stop: function (connection) {
            // Don't trigger a reconnect after stopping
            transportLogic.clearReconnectTimeout(connection);

            if (connection.socket) {
                connection.log("Closing the Websocket.");
                connection.socket.close();
                connection.socket = null;
            }
        },

        abort: function (connection, async) {
            transportLogic.ajaxAbort(connection, async);
        }
    };

}(window.jQuery, window));
/* jquery.signalR.transports.serverSentEvents.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.transports.common.js" />

(function ($, window, undefined) {

    var signalR = $.signalR,
        events = $.signalR.events,
        changeState = $.signalR.changeState,
        transportLogic = signalR.transports._logic,
        clearReconnectAttemptTimeout = function (connection) {
            window.clearTimeout(connection._.reconnectAttemptTimeoutHandle);
            delete connection._.reconnectAttemptTimeoutHandle;
        };

    signalR.transports.serverSentEvents = {
        name: "serverSentEvents",

        supportsKeepAlive: function () {
            return true;
        },

        timeOut: 3000,

        start: function (connection, onSuccess, onFailed) {
            var that = this,
                opened = false,
                $connection = $(connection),
                reconnecting = !onSuccess,
                url;

            if (connection.eventSource) {
                connection.log("The connection already has an event source. Stopping it.");
                connection.stop();
            }

            if (!window.EventSource) {
                if (onFailed) {
                    connection.log("This browser doesn't support SSE.");
                    onFailed();
                }
                return;
            }

            url = transportLogic.getUrl(connection, this.name, reconnecting);

            try {
                connection.log("Attempting to connect to SSE endpoint '" + url + "'.");
                connection.eventSource = new window.EventSource(url, { withCredentials: connection.withCredentials });
            }
            catch (e) {
                connection.log("EventSource failed trying to connect with error " + e.Message + ".");
                if (onFailed) {
                    // The connection failed, call the failed callback
                    onFailed();
                } else {
                    $connection.triggerHandler(events.onError, [signalR._.transportError(signalR.resources.eventSourceFailedToConnect, connection.transport, e)]);
                    if (reconnecting) {
                        // If we were reconnecting, rather than doing initial connect, then try reconnect again
                        that.reconnect(connection);
                    }
                }
                return;
            }

            if (reconnecting) {
                connection._.reconnectAttemptTimeoutHandle = window.setTimeout(function () {
                    if (opened === false) {
                        // If we're reconnecting and the event source is attempting to connect,
                        // don't keep retrying. This causes duplicate connections to spawn.
                        if (connection.eventSource.readyState !== window.EventSource.OPEN) {
                            // If we were reconnecting, rather than doing initial connect, then try reconnect again
                            that.reconnect(connection);
                        }
                    }
                },
                that.timeOut);
            }

            connection.eventSource.addEventListener("open", function (e) {
                connection.log("EventSource connected.");

                clearReconnectAttemptTimeout(connection);
                transportLogic.clearReconnectTimeout(connection);

                if (opened === false) {
                    opened = true;

                    if (changeState(connection,
                                         signalR.connectionState.reconnecting,
                                         signalR.connectionState.connected) === true) {
                        $connection.triggerHandler(events.onReconnect);
                    }
                }
            }, false);

            connection.eventSource.addEventListener("message", function (e) {
                var res;

                // process messages
                if (e.data === "initialized") {
                    return;
                }

                try {
                    res = connection._parseResponse(e.data);
                }
                catch (error) {
                    transportLogic.handleParseFailure(connection, e.data, error, onFailed, e);
                    return;
                }

                transportLogic.processMessages(connection, res, onSuccess);
            }, false);

            connection.eventSource.addEventListener("error", function (e) {
                var error = signalR._.transportError(
                    signalR.resources.eventSourceError,
                    connection.transport,
                    e);

                // Only handle an error if the error is from the current Event Source.
                // Sometimes on disconnect the server will push down an error event
                // to an expired Event Source.
                if (this !== connection.eventSource) {
                    return;
                }

                if (onFailed && onFailed(error)) {
                    return;
                }

                connection.log("EventSource readyState: " + connection.eventSource.readyState + ".");

                if (e.eventPhase === window.EventSource.CLOSED) {
                    // We don't use the EventSource's native reconnect function as it
                    // doesn't allow us to change the URL when reconnecting. We need
                    // to change the URL to not include the /connect suffix, and pass
                    // the last message id we received.
                    connection.log("EventSource reconnecting due to the server connection ending.");
                    that.reconnect(connection);
                } else {
                    // connection error
                    connection.log("EventSource error.");
                    $connection.triggerHandler(events.onError, [error]);
                }
            }, false);
        },

        reconnect: function (connection) {
            transportLogic.reconnect(connection, this.name);
        },

        lostConnection: function (connection) {
            this.reconnect(connection);
        },

        send: function (connection, data) {
            transportLogic.ajaxSend(connection, data);
        },

        stop: function (connection) {
            // Don't trigger a reconnect after stopping
            clearReconnectAttemptTimeout(connection);
            transportLogic.clearReconnectTimeout(connection);

            if (connection && connection.eventSource) {
                connection.log("EventSource calling close().");
                connection.eventSource.close();
                connection.eventSource = null;
                delete connection.eventSource;
            }
        },

        abort: function (connection, async) {
            transportLogic.ajaxAbort(connection, async);
        }
    };

}(window.jQuery, window));
/* jquery.signalR.transports.foreverFrame.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.transports.common.js" />

(function ($, window, undefined) {

    var signalR = $.signalR,
        events = $.signalR.events,
        changeState = $.signalR.changeState,
        transportLogic = signalR.transports._logic,
        createFrame = function () {
            var frame = window.document.createElement("iframe");
            frame.setAttribute("style", "position:absolute;top:0;left:0;width:0;height:0;visibility:hidden;");
            return frame;
        },
        // Used to prevent infinite loading icon spins in older versions of ie
        // We build this object inside a closure so we don't pollute the rest of   
        // the foreverFrame transport with unnecessary functions/utilities.
        loadPreventer = (function () {
            var loadingFixIntervalId = null,
                loadingFixInterval = 1000,
                attachedTo = 0;

            return {
                prevent: function () {
                    // Prevent additional iframe removal procedures from newer browsers
                    if (signalR._.ieVersion <= 8) {
                        // We only ever want to set the interval one time, so on the first attachedTo
                        if (attachedTo === 0) {
                            // Create and destroy iframe every 3 seconds to prevent loading icon, super hacky
                            loadingFixIntervalId = window.setInterval(function () {
                                var tempFrame = createFrame();

                                window.document.body.appendChild(tempFrame);
                                window.document.body.removeChild(tempFrame);

                                tempFrame = null;
                            }, loadingFixInterval);
                        }

                        attachedTo++;
                    }
                },
                cancel: function () {
                    // Only clear the interval if there's only one more object that the loadPreventer is attachedTo
                    if (attachedTo === 1) {
                        window.clearInterval(loadingFixIntervalId);
                    }

                    if (attachedTo > 0) {
                        attachedTo--;
                    }
                }
            };
        })();

    signalR.transports.foreverFrame = {
        name: "foreverFrame",

        supportsKeepAlive: function () {
            return true;
        },

        // Added as a value here so we can create tests to verify functionality
        iframeClearThreshold: 50,

        start: function (connection, onSuccess, onFailed) {
            var that = this,
                frameId = (transportLogic.foreverFrame.count += 1),
                url,
                frame = createFrame(),
                frameLoadHandler = function () {
                    connection.log("Forever frame iframe finished loading and is no longer receiving messages.");
                    if (!onFailed || !onFailed()) {
                        that.reconnect(connection);
                    }
                };

            if (window.EventSource) {
                // If the browser supports SSE, don't use Forever Frame
                if (onFailed) {
                    connection.log("Forever Frame is not supported by SignalR on browsers with SSE support.");
                    onFailed();
                }
                return;
            }

            frame.setAttribute("data-signalr-connection-id", connection.id);

            // Start preventing loading icon
            // This will only perform work if the loadPreventer is not attached to another connection.
            loadPreventer.prevent();

            // Build the url
            url = transportLogic.getUrl(connection, this.name);
            url += "&frameId=" + frameId;

            // add frame to the document prior to setting URL to avoid caching issues.
            window.document.documentElement.appendChild(frame);

            connection.log("Binding to iframe's load event.");

            if (frame.addEventListener) {
                frame.addEventListener("load", frameLoadHandler, false);
            } else if (frame.attachEvent) {
                frame.attachEvent("onload", frameLoadHandler);
            }

            frame.src = url;
            transportLogic.foreverFrame.connections[frameId] = connection;

            connection.frame = frame;
            connection.frameId = frameId;

            if (onSuccess) {
                connection.onSuccess = function () {
                    connection.log("Iframe transport started.");
                    onSuccess();
                };
            }
        },

        reconnect: function (connection) {
            var that = this;

            // Need to verify connection state and verify before the setTimeout occurs because an application sleep could occur during the setTimeout duration.
            if (transportLogic.isConnectedOrReconnecting(connection) && transportLogic.verifyLastActive(connection)) {
                window.setTimeout(function () {
                    // Verify that we're ok to reconnect.
                    if (!transportLogic.verifyLastActive(connection)) {
                        return;
                    }

                    if (connection.frame && transportLogic.ensureReconnectingState(connection)) {
                        var frame = connection.frame,
                            src = transportLogic.getUrl(connection, that.name, true) + "&frameId=" + connection.frameId;
                        connection.log("Updating iframe src to '" + src + "'.");
                        frame.src = src;
                    }
                }, connection.reconnectDelay);
            }
        },

        lostConnection: function (connection) {
            this.reconnect(connection);
        },

        send: function (connection, data) {
            transportLogic.ajaxSend(connection, data);
        },

        receive: function (connection, data) {
            var cw,
                body,
                response;

            if (connection.json !== connection._originalJson) {
                // If there's a custom JSON parser configured then serialize the object
                // using the original (browser) JSON parser and then deserialize it using
                // the custom parser (connection._parseResponse does that). This is so we
                // can easily send the response from the server as "raw" JSON but still 
                // support custom JSON deserialization in the browser.
                data = connection._originalJson.stringify(data);
            }

            response = connection._parseResponse(data);

            transportLogic.processMessages(connection, response, connection.onSuccess);

            // Protect against connection stopping from a callback trigger within the processMessages above.
            if (connection.state === $.signalR.connectionState.connected) {
                // Delete the script & div elements
                connection.frameMessageCount = (connection.frameMessageCount || 0) + 1;
                if (connection.frameMessageCount > signalR.transports.foreverFrame.iframeClearThreshold) {
                    connection.frameMessageCount = 0;
                    cw = connection.frame.contentWindow || connection.frame.contentDocument;
                    if (cw && cw.document && cw.document.body) {
                        body = cw.document.body;

                        // Remove all the child elements from the iframe's body to conserver memory
                        while (body.firstChild) {
                            body.removeChild(body.firstChild);
                        }
                    }
                }
            }
        },

        stop: function (connection) {
            var cw = null;

            // Stop attempting to prevent loading icon
            loadPreventer.cancel();

            if (connection.frame) {
                if (connection.frame.stop) {
                    connection.frame.stop();
                } else {
                    try {
                        cw = connection.frame.contentWindow || connection.frame.contentDocument;
                        if (cw.document && cw.document.execCommand) {
                            cw.document.execCommand("Stop");
                        }
                    }
                    catch (e) {
                        connection.log("Error occured when stopping foreverFrame transport. Message = " + e.message + ".");
                    }
                }

                // Ensure the iframe is where we left it
                if (connection.frame.parentNode === window.document.body) {
                    window.document.body.removeChild(connection.frame);
                }

                delete transportLogic.foreverFrame.connections[connection.frameId];
                connection.frame = null;
                connection.frameId = null;
                delete connection.frame;
                delete connection.frameId;
                delete connection.onSuccess;
                delete connection.frameMessageCount;
                connection.log("Stopping forever frame.");
            }
        },

        abort: function (connection, async) {
            transportLogic.ajaxAbort(connection, async);
        },

        getConnection: function (id) {
            return transportLogic.foreverFrame.connections[id];
        },

        started: function (connection) {
            if (changeState(connection,
                signalR.connectionState.reconnecting,
                signalR.connectionState.connected) === true) {

                $(connection).triggerHandler(events.onReconnect);
            }
        }
    };

}(window.jQuery, window));
/* jquery.signalR.transports.longPolling.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.transports.common.js" />

(function ($, window, undefined) {

    var signalR = $.signalR,
        events = $.signalR.events,
        changeState = $.signalR.changeState,
        isDisconnecting = $.signalR.isDisconnecting,
        transportLogic = signalR.transports._logic;

    signalR.transports.longPolling = {
        name: "longPolling",

        supportsKeepAlive: function () {
            return false;
        },

        reconnectDelay: 3000,

        start: function (connection, onSuccess, onFailed) {
            /// <summary>Starts the long polling connection</summary>
            /// <param name="connection" type="signalR">The SignalR connection to start</param>
            var that = this,
                fireConnect = function () {
                    fireConnect = $.noop;

                    connection.log("LongPolling connected.");
                    onSuccess();
                },
                tryFailConnect = function (error) {
                    if (onFailed(error)) {
                        connection.log("LongPolling failed to connect.");
                        return true;
                    }

                    return false;
                },
                privateData = connection._,
                reconnectErrors = 0,
                fireReconnected = function (instance) {
                    window.clearTimeout(privateData.reconnectTimeoutId);
                    privateData.reconnectTimeoutId = null;

                    if (changeState(instance,
                                    signalR.connectionState.reconnecting,
                                    signalR.connectionState.connected) === true) {
                        // Successfully reconnected!
                        instance.log("Raising the reconnect event");
                        $(instance).triggerHandler(events.onReconnect);
                    }
                },
                // 1 hour
                maxFireReconnectedTimeout = 3600000;

            if (connection.pollXhr) {
                connection.log("Polling xhr requests already exists, aborting.");
                connection.stop();
            }

            connection.messageId = null;

            privateData.reconnectTimeoutId = null;

            privateData.pollTimeoutId = window.setTimeout(function () {
                (function poll(instance, raiseReconnect) {
                    var messageId = instance.messageId,
                        connect = (messageId === null),
                        reconnecting = !connect,
                        polling = !raiseReconnect,
                        url = transportLogic.getUrl(instance, that.name, reconnecting, polling, true /* use Post for longPolling */),
                        postData = {};

                    if (instance.messageId) {
                        postData.messageId = instance.messageId;
                    }

                    if (instance.groupsToken) {
                        postData.groupsToken = instance.groupsToken;
                    }

                    // If we've disconnected during the time we've tried to re-instantiate the poll then stop.
                    if (isDisconnecting(instance) === true) {
                        return;
                    }

                    connection.log("Opening long polling request to '" + url + "'.");
                    instance.pollXhr = transportLogic.ajax(connection, {
                        xhrFields: {
                            onprogress: function () {
                                transportLogic.markLastMessage(connection);
                            }
                        },
                        url: url,
                        type: "POST",
                        contentType: signalR._.defaultContentType,
                        data: postData,
                        timeout: connection._.pollTimeout,
                        success: function (result) {
                            var minData,
                                delay = 0,
                                data,
                                shouldReconnect;

                            connection.log("Long poll complete.");

                            // Reset our reconnect errors so if we transition into a reconnecting state again we trigger
                            // reconnected quickly
                            reconnectErrors = 0;

                            try {
                                // Remove any keep-alives from the beginning of the result
                                minData = connection._parseResponse(result);
                            }
                            catch (error) {
                                transportLogic.handleParseFailure(instance, result, error, tryFailConnect, instance.pollXhr);
                                return;
                            }

                            // If there's currently a timeout to trigger reconnect, fire it now before processing messages
                            if (privateData.reconnectTimeoutId !== null) {
                                fireReconnected(instance);
                            }

                            if (minData) {
                                data = transportLogic.maximizePersistentResponse(minData);
                            }

                            transportLogic.processMessages(instance, minData, fireConnect);

                            if (data &&
                                $.type(data.LongPollDelay) === "number") {
                                delay = data.LongPollDelay;
                            }

                            if (isDisconnecting(instance) === true) {
                                return;
                            }

                            shouldReconnect = data && data.ShouldReconnect;
                            if (shouldReconnect) {
                                // Transition into the reconnecting state
                                // If this fails then that means that the user transitioned the connection into a invalid state in processMessages.
                                if (!transportLogic.ensureReconnectingState(instance)) {
                                    return;
                                }
                            }

                            // We never want to pass a raiseReconnect flag after a successful poll.  This is handled via the error function
                            if (delay > 0) {
                                privateData.pollTimeoutId = window.setTimeout(function () {
                                    poll(instance, shouldReconnect);
                                }, delay);
                            } else {
                                poll(instance, shouldReconnect);
                            }
                        },

                        error: function (data, textStatus) {
                            var error = signalR._.transportError(signalR.resources.longPollFailed, connection.transport, data, instance.pollXhr);

                            // Stop trying to trigger reconnect, connection is in an error state
                            // If we're not in the reconnect state this will noop
                            window.clearTimeout(privateData.reconnectTimeoutId);
                            privateData.reconnectTimeoutId = null;

                            if (textStatus === "abort") {
                                connection.log("Aborted xhr request.");
                                return;
                            }

                            if (!tryFailConnect(error)) {

                                // Increment our reconnect errors, we assume all errors to be reconnect errors
                                // In the case that it's our first error this will cause Reconnect to be fired
                                // after 1 second due to reconnectErrors being = 1.
                                reconnectErrors++;

                                if (connection.state !== signalR.connectionState.reconnecting) {
                                    connection.log("An error occurred using longPolling. Status = " + textStatus + ".  Response = " + data.responseText + ".");
                                    $(instance).triggerHandler(events.onError, [error]);
                                }

                                // We check the state here to verify that we're not in an invalid state prior to verifying Reconnect.
                                // If we're not in connected or reconnecting then the next ensureReconnectingState check will fail and will return.
                                // Therefore we don't want to change that failure code path.
                                if ((connection.state === signalR.connectionState.connected ||
                                    connection.state === signalR.connectionState.reconnecting) &&
                                    !transportLogic.verifyLastActive(connection)) {
                                    return;
                                }

                                // Transition into the reconnecting state
                                // If this fails then that means that the user transitioned the connection into the disconnected or connecting state within the above error handler trigger.
                                if (!transportLogic.ensureReconnectingState(instance)) {
                                    return;
                                }

                                // Call poll with the raiseReconnect flag as true after the reconnect delay
                                privateData.pollTimeoutId = window.setTimeout(function () {
                                    poll(instance, true);
                                }, that.reconnectDelay);
                            }
                        }
                    });

                    // This will only ever pass after an error has occured via the poll ajax procedure.
                    if (reconnecting && raiseReconnect === true) {
                        // We wait to reconnect depending on how many times we've failed to reconnect.
                        // This is essentially a heuristic that will exponentially increase in wait time before
                        // triggering reconnected.  This depends on the "error" handler of Poll to cancel this 
                        // timeout if it triggers before the Reconnected event fires.
                        // The Math.min at the end is to ensure that the reconnect timeout does not overflow.
                        privateData.reconnectTimeoutId = window.setTimeout(function () { fireReconnected(instance); }, Math.min(1000 * (Math.pow(2, reconnectErrors) - 1), maxFireReconnectedTimeout));
                    }
                }(connection));
            }, 250); // Have to delay initial poll so Chrome doesn't show loader spinner in tab
        },

        lostConnection: function (connection) {
            if (connection.pollXhr) {
                connection.pollXhr.abort("lostConnection");
            }
        },

        send: function (connection, data) {
            transportLogic.ajaxSend(connection, data);
        },

        stop: function (connection) {
            /// <summary>Stops the long polling connection</summary>
            /// <param name="connection" type="signalR">The SignalR connection to stop</param>

            window.clearTimeout(connection._.pollTimeoutId);
            window.clearTimeout(connection._.reconnectTimeoutId);

            delete connection._.pollTimeoutId;
            delete connection._.reconnectTimeoutId;

            if (connection.pollXhr) {
                connection.pollXhr.abort();
                connection.pollXhr = null;
                delete connection.pollXhr;
            }
        },

        abort: function (connection, async) {
            transportLogic.ajaxAbort(connection, async);
        }
    };

}(window.jQuery, window));
/* jquery.signalR.hubs.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.core.js" />

(function ($, window, undefined) {

    var eventNamespace = ".hubProxy",
        signalR = $.signalR;

    function makeEventName(event) {
        return event + eventNamespace;
    }

    // Equivalent to Array.prototype.map
    function map(arr, fun, thisp) {
        var i,
            length = arr.length,
            result = [];
        for (i = 0; i < length; i += 1) {
            if (arr.hasOwnProperty(i)) {
                result[i] = fun.call(thisp, arr[i], i, arr);
            }
        }
        return result;
    }

    function getArgValue(a) {
        return $.isFunction(a) ? null : ($.type(a) === "undefined" ? null : a);
    }

    function hasMembers(obj) {
        for (var key in obj) {
            // If we have any properties in our callback map then we have callbacks and can exit the loop via return
            if (obj.hasOwnProperty(key)) {
                return true;
            }
        }

        return false;
    }

    function clearInvocationCallbacks(connection, error) {
        /// <param name="connection" type="hubConnection" />
        var callbacks = connection._.invocationCallbacks,
            callback;

        if (hasMembers(callbacks)) {
            connection.log("Clearing hub invocation callbacks with error: " + error + ".");
        }

        // Reset the callback cache now as we have a local var referencing it
        connection._.invocationCallbackId = 0;
        delete connection._.invocationCallbacks;
        connection._.invocationCallbacks = {};

        // Loop over the callbacks and invoke them.
        // We do this using a local var reference and *after* we've cleared the cache
        // so that if a fail callback itself tries to invoke another method we don't 
        // end up with its callback in the list we're looping over.
        for (var callbackId in callbacks) {
            callback = callbacks[callbackId];
            callback.method.call(callback.scope, { E: error });
        }
    }

    // hubProxy
    function hubProxy(hubConnection, hubName) {
        /// <summary>
        ///     Creates a new proxy object for the given hub connection that can be used to invoke
        ///     methods on server hubs and handle client method invocation requests from the server.
        /// </summary>
        return new hubProxy.fn.init(hubConnection, hubName);
    }

    hubProxy.fn = hubProxy.prototype = {
        init: function (connection, hubName) {
            this.state = {};
            this.connection = connection;
            this.hubName = hubName;
            this._ = {
                callbackMap: {}
            };
        },

        constructor: hubProxy,

        hasSubscriptions: function () {
            return hasMembers(this._.callbackMap);
        },

        on: function (eventName, callback) {
            /// <summary>Wires up a callback to be invoked when a invocation request is received from the server hub.</summary>
            /// <param name="eventName" type="String">The name of the hub event to register the callback for.</param>
            /// <param name="callback" type="Function">The callback to be invoked.</param>
            var that = this,
                callbackMap = that._.callbackMap;

            // Normalize the event name to lowercase
            eventName = eventName.toLowerCase();

            // If there is not an event registered for this callback yet we want to create its event space in the callback map.
            if (!callbackMap[eventName]) {
                callbackMap[eventName] = {};
            }

            // Map the callback to our encompassed function
            callbackMap[eventName][callback] = function (e, data) {
                callback.apply(that, data);
            };

            $(that).bind(makeEventName(eventName), callbackMap[eventName][callback]);

            return that;
        },

        off: function (eventName, callback) {
            /// <summary>Removes the callback invocation request from the server hub for the given event name.</summary>
            /// <param name="eventName" type="String">The name of the hub event to unregister the callback for.</param>
            /// <param name="callback" type="Function">The callback to be invoked.</param>
            var that = this,
                callbackMap = that._.callbackMap,
                callbackSpace;

            // Normalize the event name to lowercase
            eventName = eventName.toLowerCase();

            callbackSpace = callbackMap[eventName];

            // Verify that there is an event space to unbind
            if (callbackSpace) {
                // Only unbind if there's an event bound with eventName and a callback with the specified callback
                if (callbackSpace[callback]) {
                    $(that).unbind(makeEventName(eventName), callbackSpace[callback]);

                    // Remove the callback from the callback map
                    delete callbackSpace[callback];

                    // Check if there are any members left on the event, if not we need to destroy it.
                    if (!hasMembers(callbackSpace)) {
                        delete callbackMap[eventName];
                    }
                } else if (!callback) { // Check if we're removing the whole event and we didn't error because of an invalid callback
                    $(that).unbind(makeEventName(eventName));

                    delete callbackMap[eventName];
                }
            }

            return that;
        },

        invoke: function (methodName) {
            /// <summary>Invokes a server hub method with the given arguments.</summary>
            /// <param name="methodName" type="String">The name of the server hub method.</param>

            var that = this,
                connection = that.connection,
                args = $.makeArray(arguments).slice(1),
                argValues = map(args, getArgValue),
                data = { H: that.hubName, M: methodName, A: argValues, I: connection._.invocationCallbackId },
                d = $.Deferred(),
                callback = function (minResult) {
                    var result = that._maximizeHubResponse(minResult),
                        source,
                        error;

                    // Update the hub state
                    $.extend(that.state, result.State);

                    if (result.Progress) {
                        if (d.notifyWith) {
                            // Progress is only supported in jQuery 1.7+
                            d.notifyWith(that, [result.Progress.Data]);
                        } else if(!connection._.progressjQueryVersionLogged) {
                            connection.log("A hub method invocation progress update was received but the version of jQuery in use (" + $.prototype.jquery + ") does not support progress updates. Upgrade to jQuery 1.7+ to receive progress notifications.");
                            connection._.progressjQueryVersionLogged = true;
                        }
                    } else if (result.Error) {
                        // Server hub method threw an exception, log it & reject the deferred
                        if (result.StackTrace) {
                            connection.log(result.Error + "\n" + result.StackTrace + ".");
                        }

                        // result.ErrorData is only set if a HubException was thrown
                        source = result.IsHubException ? "HubException" : "Exception";
                        error = signalR._.error(result.Error, source);
                        error.data = result.ErrorData;

                        connection.log(that.hubName + "." + methodName + " failed to execute. Error: " + error.message);
                        d.rejectWith(that, [error]);
                    } else {
                        // Server invocation succeeded, resolve the deferred
                        connection.log("Invoked " + that.hubName + "." + methodName);
                        d.resolveWith(that, [result.Result]);
                    }
                };

            connection._.invocationCallbacks[connection._.invocationCallbackId.toString()] = { scope: that, method: callback };
            connection._.invocationCallbackId += 1;

            if (!$.isEmptyObject(that.state)) {
                data.S = that.state;
            }

            connection.log("Invoking " + that.hubName + "." + methodName);
            connection.send(data);

            return d.promise();
        },

        _maximizeHubResponse: function (minHubResponse) {
            return {
                State: minHubResponse.S,
                Result: minHubResponse.R,
                Progress: minHubResponse.P ? {
                    Id: minHubResponse.P.I,
                    Data: minHubResponse.P.D
                } : null,
                Id: minHubResponse.I,
                IsHubException: minHubResponse.H,
                Error: minHubResponse.E,
                StackTrace: minHubResponse.T,
                ErrorData: minHubResponse.D
            };
        }
    };

    hubProxy.fn.init.prototype = hubProxy.fn;

    // hubConnection
    function hubConnection(url, options) {
        /// <summary>Creates a new hub connection.</summary>
        /// <param name="url" type="String">[Optional] The hub route url, defaults to "/signalr".</param>
        /// <param name="options" type="Object">[Optional] Settings to use when creating the hubConnection.</param>
        var settings = {
            qs: null,
            logging: false,
            useDefaultPath: true
        };

        $.extend(settings, options);

        if (!url || settings.useDefaultPath) {
            url = (url || "") + "/signalr";
        }
        return new hubConnection.fn.init(url, settings);
    }

    hubConnection.fn = hubConnection.prototype = $.connection();

    hubConnection.fn.init = function (url, options) {
        var settings = {
                qs: null,
                logging: false,
                useDefaultPath: true
            },
            connection = this;

        $.extend(settings, options);

        // Call the base constructor
        $.signalR.fn.init.call(connection, url, settings.qs, settings.logging);

        // Object to store hub proxies for this connection
        connection.proxies = {};

        connection._.invocationCallbackId = 0;
        connection._.invocationCallbacks = {};

        // Wire up the received handler
        connection.received(function (minData) {
            var data, proxy, dataCallbackId, callback, hubName, eventName;
            if (!minData) {
                return;
            }

            // We have to handle progress updates first in order to ensure old clients that receive
            // progress updates enter the return value branch and then no-op when they can't find
            // the callback in the map (because the minData.I value will not be a valid callback ID)
            if (typeof (minData.P) !== "undefined") {
                // Process progress notification
                dataCallbackId = minData.P.I.toString();
                callback = connection._.invocationCallbacks[dataCallbackId];
                if (callback) {
                    callback.method.call(callback.scope, minData);
                }
            } else if (typeof (minData.I) !== "undefined") {
                // We received the return value from a server method invocation, look up callback by id and call it
                dataCallbackId = minData.I.toString();
                callback = connection._.invocationCallbacks[dataCallbackId];
                if (callback) {
                    // Delete the callback from the proxy
                    connection._.invocationCallbacks[dataCallbackId] = null;
                    delete connection._.invocationCallbacks[dataCallbackId];

                    // Invoke the callback
                    callback.method.call(callback.scope, minData);
                }
            } else {
                data = this._maximizeClientHubInvocation(minData);

                // We received a client invocation request, i.e. broadcast from server hub
                connection.log("Triggering client hub event '" + data.Method + "' on hub '" + data.Hub + "'.");

                // Normalize the names to lowercase
                hubName = data.Hub.toLowerCase();
                eventName = data.Method.toLowerCase();

                // Trigger the local invocation event
                proxy = this.proxies[hubName];

                // Update the hub state
                $.extend(proxy.state, data.State);
                $(proxy).triggerHandler(makeEventName(eventName), [data.Args]);
            }
        });

        connection.error(function (errData, origData) {
            var callbackId, callback;

            if (!origData) {
                // No original data passed so this is not a send error
                return;
            }

            callbackId = origData.I;
            callback = connection._.invocationCallbacks[callbackId];

            // Verify that there is a callback bound (could have been cleared)
            if (callback) {
                // Delete the callback
                connection._.invocationCallbacks[callbackId] = null;
                delete connection._.invocationCallbacks[callbackId];

                // Invoke the callback with an error to reject the promise
                callback.method.call(callback.scope, { E: errData });
            }
        });

        connection.reconnecting(function () {
            if (connection.transport && connection.transport.name === "webSockets") {
                clearInvocationCallbacks(connection, "Connection started reconnecting before invocation result was received.");
            }
        });

        connection.disconnected(function () {
            clearInvocationCallbacks(connection, "Connection was disconnected before invocation result was received.");
        });
    };

    hubConnection.fn._maximizeClientHubInvocation = function (minClientHubInvocation) {
        return {
            Hub: minClientHubInvocation.H,
            Method: minClientHubInvocation.M,
            Args: minClientHubInvocation.A,
            State: minClientHubInvocation.S
        };
    };

    hubConnection.fn._registerSubscribedHubs = function () {
        /// <summary>
        ///     Sets the starting event to loop through the known hubs and register any new hubs 
        ///     that have been added to the proxy.
        /// </summary>
        var connection = this;

        if (!connection._subscribedToHubs) {
            connection._subscribedToHubs = true;
            connection.starting(function () {
                // Set the connection's data object with all the hub proxies with active subscriptions.
                // These proxies will receive notifications from the server.
                var subscribedHubs = [];

                $.each(connection.proxies, function (key) {
                    if (this.hasSubscriptions()) {
                        subscribedHubs.push({ name: key });
                        connection.log("Client subscribed to hub '" + key + "'.");
                    }
                });

                if (subscribedHubs.length === 0) {
                    connection.log("No hubs have been subscribed to.  The client will not receive data from hubs.  To fix, declare at least one client side function prior to connection start for each hub you wish to subscribe to.");
                }

                connection.data = connection.json.stringify(subscribedHubs);
            });
        }
    };

    hubConnection.fn.createHubProxy = function (hubName) {
        /// <summary>
        ///     Creates a new proxy object for the given hub connection that can be used to invoke
        ///     methods on server hubs and handle client method invocation requests from the server.
        /// </summary>
        /// <param name="hubName" type="String">
        ///     The name of the hub on the server to create the proxy for.
        /// </param>

        // Normalize the name to lowercase
        hubName = hubName.toLowerCase();

        var proxy = this.proxies[hubName];
        if (!proxy) {
            proxy = hubProxy(this, hubName);
            this.proxies[hubName] = proxy;
        }

        this._registerSubscribedHubs();

        return proxy;
    };

    hubConnection.fn.init.prototype = hubConnection.fn;

    $.hubConnection = hubConnection;

}(window.jQuery, window));
/* jquery.signalR.version.js */
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.

/*global window:false */
/// <reference path="jquery.signalR.core.js" />
(function ($, undefined) {
    $.signalR.version = "2.2.0";
}(window.jQuery));

},{}],196:[function(require,module,exports){
/**!
 * Sortable
 * @author	RubaXa   <trash@rubaxa.org>
 * @license MIT
 */


(function (factory) {
	"use strict";

	if (typeof define === "function" && define.amd) {
		define(factory);
	}
	else if (typeof module != "undefined" && typeof module.exports != "undefined") {
		module.exports = factory();
	}
	else if (typeof Package !== "undefined") {
		var Sortable = factory();  // export for Meteor.js
	}
	else {
		/* jshint sub:true */
		window["Sortable"] = factory();
	}
})(function () {
	"use strict";

	var dragEl,
		parentEl,
		ghostEl,
		cloneEl,
		rootEl,
		nextEl,

		scrollEl,
		scrollParentEl,

		lastEl,
		lastCSS,
		lastParentCSS,

		oldIndex,
		newIndex,

		activeGroup,
		autoScroll = {},

		tapEvt,
		touchEvt,

		moved,

		/** @const */
		RSPACE = /\s+/g,

		expando = 'Sortable' + (new Date).getTime(),

		win = window,
		document = win.document,
		parseInt = win.parseInt,

		supportDraggable = !!('draggable' in document.createElement('div')),
		supportCssPointerEvents = (function (el) {
			el = document.createElement('x');
			el.style.cssText = 'pointer-events:auto';
			return el.style.pointerEvents === 'auto';
		})(),

		_silent = false,

		abs = Math.abs,
		slice = [].slice,

		touchDragOverListeners = [],

		_autoScroll = _throttle(function (/**Event*/evt, /**Object*/options, /**HTMLElement*/rootEl) {
			// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
			if (rootEl && options.scroll) {
				var el,
					rect,
					sens = options.scrollSensitivity,
					speed = options.scrollSpeed,

					x = evt.clientX,
					y = evt.clientY,

					winWidth = window.innerWidth,
					winHeight = window.innerHeight,

					vx,
					vy
				;

				// Delect scrollEl
				if (scrollParentEl !== rootEl) {
					scrollEl = options.scroll;
					scrollParentEl = rootEl;

					if (scrollEl === true) {
						scrollEl = rootEl;

						do {
							if ((scrollEl.offsetWidth < scrollEl.scrollWidth) ||
								(scrollEl.offsetHeight < scrollEl.scrollHeight)
							) {
								break;
							}
							/* jshint boss:true */
						} while (scrollEl = scrollEl.parentNode);
					}
				}

				if (scrollEl) {
					el = scrollEl;
					rect = scrollEl.getBoundingClientRect();
					vx = (abs(rect.right - x) <= sens) - (abs(rect.left - x) <= sens);
					vy = (abs(rect.bottom - y) <= sens) - (abs(rect.top - y) <= sens);
				}


				if (!(vx || vy)) {
					vx = (winWidth - x <= sens) - (x <= sens);
					vy = (winHeight - y <= sens) - (y <= sens);

					/* jshint expr:true */
					(vx || vy) && (el = win);
				}


				if (autoScroll.vx !== vx || autoScroll.vy !== vy || autoScroll.el !== el) {
					autoScroll.el = el;
					autoScroll.vx = vx;
					autoScroll.vy = vy;

					clearInterval(autoScroll.pid);

					if (el) {
						autoScroll.pid = setInterval(function () {
							if (el === win) {
								win.scrollTo(win.pageXOffset + vx * speed, win.pageYOffset + vy * speed);
							} else {
								vy && (el.scrollTop += vy * speed);
								vx && (el.scrollLeft += vx * speed);
							}
						}, 24);
					}
				}
			}
		}, 30),

		_prepareGroup = function (options) {
			var group = options.group;

			if (!group || typeof group != 'object') {
				group = options.group = {name: group};
			}

			['pull', 'put'].forEach(function (key) {
				if (!(key in group)) {
					group[key] = true;
				}
			});

			options.groups = ' ' + group.name + (group.put.join ? ' ' + group.put.join(' ') : '') + ' ';
		}
	;



	/**
	 * @class  Sortable
	 * @param  {HTMLElement}  el
	 * @param  {Object}       [options]
	 */
	function Sortable(el, options) {
		if (!(el && el.nodeType && el.nodeType === 1)) {
			throw 'Sortable: `el` must be HTMLElement, and not ' + {}.toString.call(el);
		}

		this.el = el; // root element
		this.options = options = _extend({}, options);


		// Export instance
		el[expando] = this;


		// Default options
		var defaults = {
			group: Math.random(),
			sort: true,
			disabled: false,
			store: null,
			handle: null,
			scroll: true,
			scrollSensitivity: 30,
			scrollSpeed: 10,
			draggable: /[uo]l/i.test(el.nodeName) ? 'li' : '>*',
			ghostClass: 'sortable-ghost',
			chosenClass: 'sortable-chosen',
			ignore: 'a, img',
			filter: null,
			animation: 0,
			setData: function (dataTransfer, dragEl) {
				dataTransfer.setData('Text', dragEl.textContent);
			},
			dropBubble: false,
			dragoverBubble: false,
			dataIdAttr: 'data-id',
			delay: 0,
			forceFallback: false,
			fallbackClass: 'sortable-fallback',
			fallbackOnBody: false
		};


		// Set default options
		for (var name in defaults) {
			!(name in options) && (options[name] = defaults[name]);
		}

		_prepareGroup(options);

		// Bind all private methods
		for (var fn in this) {
			if (fn.charAt(0) === '_') {
				this[fn] = this[fn].bind(this);
			}
		}

		// Setup drag mode
		this.nativeDraggable = options.forceFallback ? false : supportDraggable;

		// Bind events
		_on(el, 'mousedown', this._onTapStart);
		_on(el, 'touchstart', this._onTapStart);

		if (this.nativeDraggable) {
			_on(el, 'dragover', this);
			_on(el, 'dragenter', this);
		}

		touchDragOverListeners.push(this._onDragOver);

		// Restore sorting
		options.store && this.sort(options.store.get(this));
	}


	Sortable.prototype = /** @lends Sortable.prototype */ {
		constructor: Sortable,

		_onTapStart: function (/** Event|TouchEvent */evt) {
			var _this = this,
				el = this.el,
				options = this.options,
				type = evt.type,
				touch = evt.touches && evt.touches[0],
				target = (touch || evt).target,
				originalTarget = target,
				filter = options.filter;


			if (type === 'mousedown' && evt.button !== 0 || options.disabled) {
				return; // only left button or enabled
			}

			target = _closest(target, options.draggable, el);

			if (!target) {
				return;
			}

			// get the index of the dragged element within its parent
			oldIndex = _index(target);

			// Check filter
			if (typeof filter === 'function') {
				if (filter.call(this, evt, target, this)) {
					_dispatchEvent(_this, originalTarget, 'filter', target, el, oldIndex);
					evt.preventDefault();
					return; // cancel dnd
				}
			}
			else if (filter) {
				filter = filter.split(',').some(function (criteria) {
					criteria = _closest(originalTarget, criteria.trim(), el);

					if (criteria) {
						_dispatchEvent(_this, criteria, 'filter', target, el, oldIndex);
						return true;
					}
				});

				if (filter) {
					evt.preventDefault();
					return; // cancel dnd
				}
			}


			if (options.handle && !_closest(originalTarget, options.handle, el)) {
				return;
			}


			// Prepare `dragstart`
			this._prepareDragStart(evt, touch, target);
		},

		_prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target) {
			var _this = this,
				el = _this.el,
				options = _this.options,
				ownerDocument = el.ownerDocument,
				dragStartFn;

			if (target && !dragEl && (target.parentNode === el)) {
				tapEvt = evt;

				rootEl = el;
				dragEl = target;
				parentEl = dragEl.parentNode;
				nextEl = dragEl.nextSibling;
				activeGroup = options.group;

				dragStartFn = function () {
					// Delayed drag has been triggered
					// we can re-enable the events: touchmove/mousemove
					_this._disableDelayedDrag();

					// Make the element draggable
					dragEl.draggable = true;

					// Chosen item
					_toggleClass(dragEl, _this.options.chosenClass, true);

					// Bind the events: dragstart/dragend
					_this._triggerDragStart(touch);
				};

				// Disable "draggable"
				options.ignore.split(',').forEach(function (criteria) {
					_find(dragEl, criteria.trim(), _disableDraggable);
				});

				_on(ownerDocument, 'mouseup', _this._onDrop);
				_on(ownerDocument, 'touchend', _this._onDrop);
				_on(ownerDocument, 'touchcancel', _this._onDrop);

				if (options.delay) {
					// If the user moves the pointer or let go the click or touch
					// before the delay has been reached:
					// disable the delayed drag
					_on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
					_on(ownerDocument, 'touchend', _this._disableDelayedDrag);
					_on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
					_on(ownerDocument, 'mousemove', _this._disableDelayedDrag);
					_on(ownerDocument, 'touchmove', _this._disableDelayedDrag);

					_this._dragStartTimer = setTimeout(dragStartFn, options.delay);
				} else {
					dragStartFn();
				}
			}
		},

		_disableDelayedDrag: function () {
			var ownerDocument = this.el.ownerDocument;

			clearTimeout(this._dragStartTimer);
			_off(ownerDocument, 'mouseup', this._disableDelayedDrag);
			_off(ownerDocument, 'touchend', this._disableDelayedDrag);
			_off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
			_off(ownerDocument, 'mousemove', this._disableDelayedDrag);
			_off(ownerDocument, 'touchmove', this._disableDelayedDrag);
		},

		_triggerDragStart: function (/** Touch */touch) {
			if (touch) {
				// Touch device support
				tapEvt = {
					target: dragEl,
					clientX: touch.clientX,
					clientY: touch.clientY
				};

				this._onDragStart(tapEvt, 'touch');
			}
			else if (!this.nativeDraggable) {
				this._onDragStart(tapEvt, true);
			}
			else {
				_on(dragEl, 'dragend', this);
				_on(rootEl, 'dragstart', this._onDragStart);
			}

			try {
				if (document.selection) {
					document.selection.empty();
				} else {
					window.getSelection().removeAllRanges();
				}
			} catch (err) {
			}
		},

		_dragStarted: function () {
			if (rootEl && dragEl) {
				// Apply effect
				_toggleClass(dragEl, this.options.ghostClass, true);

				Sortable.active = this;

				// Drag start event
				_dispatchEvent(this, rootEl, 'start', dragEl, rootEl, oldIndex);
			}
		},

		_emulateDragOver: function () {
			if (touchEvt) {
				if (this._lastX === touchEvt.clientX && this._lastY === touchEvt.clientY) {
					return;
				}

				this._lastX = touchEvt.clientX;
				this._lastY = touchEvt.clientY;

				if (!supportCssPointerEvents) {
					_css(ghostEl, 'display', 'none');
				}

				var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY),
					parent = target,
					groupName = ' ' + this.options.group.name + '',
					i = touchDragOverListeners.length;

				if (parent) {
					do {
						if (parent[expando] && parent[expando].options.groups.indexOf(groupName) > -1) {
							while (i--) {
								touchDragOverListeners[i]({
									clientX: touchEvt.clientX,
									clientY: touchEvt.clientY,
									target: target,
									rootEl: parent
								});
							}

							break;
						}

						target = parent; // store last element
					}
					/* jshint boss:true */
					while (parent = parent.parentNode);
				}

				if (!supportCssPointerEvents) {
					_css(ghostEl, 'display', '');
				}
			}
		},


		_onTouchMove: function (/**TouchEvent*/evt) {
			if (tapEvt) {
				// only set the status to dragging, when we are actually dragging
				if (!Sortable.active) {
					this._dragStarted();
				}

				// as well as creating the ghost element on the document body
				this._appendGhost();

				var touch = evt.touches ? evt.touches[0] : evt,
					dx = touch.clientX - tapEvt.clientX,
					dy = touch.clientY - tapEvt.clientY,
					translate3d = evt.touches ? 'translate3d(' + dx + 'px,' + dy + 'px,0)' : 'translate(' + dx + 'px,' + dy + 'px)';

				moved = true;
				touchEvt = touch;

				_css(ghostEl, 'webkitTransform', translate3d);
				_css(ghostEl, 'mozTransform', translate3d);
				_css(ghostEl, 'msTransform', translate3d);
				_css(ghostEl, 'transform', translate3d);

				evt.preventDefault();
			}
		},

		_appendGhost: function () {
			if (!ghostEl) {
				var rect = dragEl.getBoundingClientRect(),
					css = _css(dragEl),
					ghostRect;

				ghostEl = dragEl.cloneNode(true);

				_toggleClass(ghostEl, this.options.ghostClass, false);
				_toggleClass(ghostEl, this.options.fallbackClass, true);

				_css(ghostEl, 'top', rect.top - parseInt(css.marginTop, 10));
				_css(ghostEl, 'left', rect.left - parseInt(css.marginLeft, 10));
				_css(ghostEl, 'width', rect.width);
				_css(ghostEl, 'height', rect.height);
				_css(ghostEl, 'opacity', '0.8');
				_css(ghostEl, 'position', 'fixed');
				_css(ghostEl, 'zIndex', '100000');
				_css(ghostEl, 'pointerEvents', 'none');

				this.options.fallbackOnBody && document.body.appendChild(ghostEl) || rootEl.appendChild(ghostEl);

				// Fixing dimensions.
				ghostRect = ghostEl.getBoundingClientRect();
				_css(ghostEl, 'width', rect.width * 2 - ghostRect.width);
				_css(ghostEl, 'height', rect.height * 2 - ghostRect.height);
			}
		},

		_onDragStart: function (/**Event*/evt, /**boolean*/useFallback) {
			var dataTransfer = evt.dataTransfer,
				options = this.options;

			this._offUpEvents();

			if (activeGroup.pull == 'clone') {
				cloneEl = dragEl.cloneNode(true);
				_css(cloneEl, 'display', 'none');
				rootEl.insertBefore(cloneEl, dragEl);
			}

			if (useFallback) {

				if (useFallback === 'touch') {
					// Bind touch events
					_on(document, 'touchmove', this._onTouchMove);
					_on(document, 'touchend', this._onDrop);
					_on(document, 'touchcancel', this._onDrop);
				} else {
					// Old brwoser
					_on(document, 'mousemove', this._onTouchMove);
					_on(document, 'mouseup', this._onDrop);
				}

				this._loopId = setInterval(this._emulateDragOver, 50);
			}
			else {
				if (dataTransfer) {
					dataTransfer.effectAllowed = 'move';
					options.setData && options.setData.call(this, dataTransfer, dragEl);
				}

				_on(document, 'drop', this);
				setTimeout(this._dragStarted, 0);
			}
		},

		_onDragOver: function (/**Event*/evt) {
			var el = this.el,
				target,
				dragRect,
				revert,
				options = this.options,
				group = options.group,
				groupPut = group.put,
				isOwner = (activeGroup === group),
				canSort = options.sort;

			if (evt.preventDefault !== void 0) {
				evt.preventDefault();
				!options.dragoverBubble && evt.stopPropagation();
			}

			moved = true;

			if (activeGroup && !options.disabled &&
				(isOwner
					? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
					: activeGroup.pull && groupPut && (
						(activeGroup.name === group.name) || // by Name
						(groupPut.indexOf && ~groupPut.indexOf(activeGroup.name)) // by Array
					)
				) &&
				(evt.rootEl === void 0 || evt.rootEl === this.el) // touch fallback
			) {
				// Smart auto-scrolling
				_autoScroll(evt, options, this.el);

				if (_silent) {
					return;
				}

				target = _closest(evt.target, options.draggable, el);
				dragRect = dragEl.getBoundingClientRect();

				if (revert) {
					_cloneHide(true);

					if (cloneEl || nextEl) {
						rootEl.insertBefore(dragEl, cloneEl || nextEl);
					}
					else if (!canSort) {
						rootEl.appendChild(dragEl);
					}

					return;
				}


				if ((el.children.length === 0) || (el.children[0] === ghostEl) ||
					(el === evt.target) && (target = _ghostIsLast(el, evt))
				) {

					if (target) {
						if (target.animated) {
							return;
						}

						targetRect = target.getBoundingClientRect();
					}

					_cloneHide(isOwner);

					if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect) !== false) {
						if (!dragEl.contains(el)) {
							el.appendChild(dragEl);
							parentEl = el; // actualization
						}

						this._animate(dragRect, dragEl);
						target && this._animate(targetRect, target);
					}
				}
				else if (target && !target.animated && target !== dragEl && (target.parentNode[expando] !== void 0)) {
					if (lastEl !== target) {
						lastEl = target;
						lastCSS = _css(target);
						lastParentCSS = _css(target.parentNode);
					}


					var targetRect = target.getBoundingClientRect(),
						width = targetRect.right - targetRect.left,
						height = targetRect.bottom - targetRect.top,
						floating = /left|right|inline/.test(lastCSS.cssFloat + lastCSS.display)
							|| (lastParentCSS.display == 'flex' && lastParentCSS['flex-direction'].indexOf('row') === 0),
						isWide = (target.offsetWidth > dragEl.offsetWidth),
						isLong = (target.offsetHeight > dragEl.offsetHeight),
						halfway = (floating ? (evt.clientX - targetRect.left) / width : (evt.clientY - targetRect.top) / height) > 0.5,
						nextSibling = target.nextElementSibling,
						moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect),
						after
					;

					if (moveVector !== false) {
						_silent = true;
						setTimeout(_unsilent, 30);

						_cloneHide(isOwner);

						if (moveVector === 1 || moveVector === -1) {
							after = (moveVector === 1);
						}
						else if (floating) {
							var elTop = dragEl.offsetTop,
								tgTop = target.offsetTop;

							if (elTop === tgTop) {
								after = (target.previousElementSibling === dragEl) && !isWide || halfway && isWide;
							} else {
								after = tgTop > elTop;
							}
						} else {
							after = (nextSibling !== dragEl) && !isLong || halfway && isLong;
						}

						if (!dragEl.contains(el)) {
							if (after && !nextSibling) {
								el.appendChild(dragEl);
							} else {
								target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
							}
						}

						parentEl = dragEl.parentNode; // actualization

						this._animate(dragRect, dragEl);
						this._animate(targetRect, target);
					}
				}
			}
		},

		_animate: function (prevRect, target) {
			var ms = this.options.animation;

			if (ms) {
				var currentRect = target.getBoundingClientRect();

				_css(target, 'transition', 'none');
				_css(target, 'transform', 'translate3d('
					+ (prevRect.left - currentRect.left) + 'px,'
					+ (prevRect.top - currentRect.top) + 'px,0)'
				);

				target.offsetWidth; // repaint

				_css(target, 'transition', 'all ' + ms + 'ms');
				_css(target, 'transform', 'translate3d(0,0,0)');

				clearTimeout(target.animated);
				target.animated = setTimeout(function () {
					_css(target, 'transition', '');
					_css(target, 'transform', '');
					target.animated = false;
				}, ms);
			}
		},

		_offUpEvents: function () {
			var ownerDocument = this.el.ownerDocument;

			_off(document, 'touchmove', this._onTouchMove);
			_off(ownerDocument, 'mouseup', this._onDrop);
			_off(ownerDocument, 'touchend', this._onDrop);
			_off(ownerDocument, 'touchcancel', this._onDrop);
		},

		_onDrop: function (/**Event*/evt) {
			var el = this.el,
				options = this.options;

			clearInterval(this._loopId);
			clearInterval(autoScroll.pid);
			clearTimeout(this._dragStartTimer);

			// Unbind events
			_off(document, 'mousemove', this._onTouchMove);

			if (this.nativeDraggable) {
				_off(document, 'drop', this);
				_off(el, 'dragstart', this._onDragStart);
			}

			this._offUpEvents();

			if (evt) {
				if (moved) {
					evt.preventDefault();
					!options.dropBubble && evt.stopPropagation();
				}

				ghostEl && ghostEl.parentNode.removeChild(ghostEl);

				if (dragEl) {
					if (this.nativeDraggable) {
						_off(dragEl, 'dragend', this);
					}

					_disableDraggable(dragEl);

					// Remove class's
					_toggleClass(dragEl, this.options.ghostClass, false);
					_toggleClass(dragEl, this.options.chosenClass, false);

					if (rootEl !== parentEl) {
						newIndex = _index(dragEl);

						if (newIndex >= 0) {
							// drag from one list and drop into another
							_dispatchEvent(null, parentEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
							_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);

							// Add event
							_dispatchEvent(null, parentEl, 'add', dragEl, rootEl, oldIndex, newIndex);

							// Remove event
							_dispatchEvent(this, rootEl, 'remove', dragEl, rootEl, oldIndex, newIndex);
						}
					}
					else {
						// Remove clone
						cloneEl && cloneEl.parentNode.removeChild(cloneEl);

						if (dragEl.nextSibling !== nextEl) {
							// Get the index of the dragged element within its parent
							newIndex = _index(dragEl);

							if (newIndex >= 0) {
								// drag & drop within the same list
								_dispatchEvent(this, rootEl, 'update', dragEl, rootEl, oldIndex, newIndex);
								_dispatchEvent(this, rootEl, 'sort', dragEl, rootEl, oldIndex, newIndex);
							}
						}
					}

					if (Sortable.active) {
						if (newIndex === null || newIndex === -1) {
							newIndex = oldIndex;
						}

						_dispatchEvent(this, rootEl, 'end', dragEl, rootEl, oldIndex, newIndex);

						// Save sorting
						this.save();
					}
				}

				// Nulling
				rootEl =
				dragEl =
				parentEl =
				ghostEl =
				nextEl =
				cloneEl =

				scrollEl =
				scrollParentEl =

				tapEvt =
				touchEvt =

				moved =
				newIndex =

				lastEl =
				lastCSS =

				activeGroup =
				Sortable.active = null;
			}
		},


		handleEvent: function (/**Event*/evt) {
			var type = evt.type;

			if (type === 'dragover' || type === 'dragenter') {
				if (dragEl) {
					this._onDragOver(evt);
					_globalDragOver(evt);
				}
			}
			else if (type === 'drop' || type === 'dragend') {
				this._onDrop(evt);
			}
		},


		/**
		 * Serializes the item into an array of string.
		 * @returns {String[]}
		 */
		toArray: function () {
			var order = [],
				el,
				children = this.el.children,
				i = 0,
				n = children.length,
				options = this.options;

			for (; i < n; i++) {
				el = children[i];
				if (_closest(el, options.draggable, this.el)) {
					order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
				}
			}

			return order;
		},


		/**
		 * Sorts the elements according to the array.
		 * @param  {String[]}  order  order of the items
		 */
		sort: function (order) {
			var items = {}, rootEl = this.el;

			this.toArray().forEach(function (id, i) {
				var el = rootEl.children[i];

				if (_closest(el, this.options.draggable, rootEl)) {
					items[id] = el;
				}
			}, this);

			order.forEach(function (id) {
				if (items[id]) {
					rootEl.removeChild(items[id]);
					rootEl.appendChild(items[id]);
				}
			});
		},


		/**
		 * Save the current sorting
		 */
		save: function () {
			var store = this.options.store;
			store && store.set(this);
		},


		/**
		 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
		 * @param   {HTMLElement}  el
		 * @param   {String}       [selector]  default: `options.draggable`
		 * @returns {HTMLElement|null}
		 */
		closest: function (el, selector) {
			return _closest(el, selector || this.options.draggable, this.el);
		},


		/**
		 * Set/get option
		 * @param   {string} name
		 * @param   {*}      [value]
		 * @returns {*}
		 */
		option: function (name, value) {
			var options = this.options;

			if (value === void 0) {
				return options[name];
			} else {
				options[name] = value;

				if (name === 'group') {
					_prepareGroup(options);
				}
			}
		},


		/**
		 * Destroy
		 */
		destroy: function () {
			var el = this.el;

			el[expando] = null;

			_off(el, 'mousedown', this._onTapStart);
			_off(el, 'touchstart', this._onTapStart);

			if (this.nativeDraggable) {
				_off(el, 'dragover', this);
				_off(el, 'dragenter', this);
			}

			// Remove draggable attributes
			Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
				el.removeAttribute('draggable');
			});

			touchDragOverListeners.splice(touchDragOverListeners.indexOf(this._onDragOver), 1);

			this._onDrop();

			this.el = el = null;
		}
	};


	function _cloneHide(state) {
		if (cloneEl && (cloneEl.state !== state)) {
			_css(cloneEl, 'display', state ? 'none' : '');
			!state && cloneEl.state && rootEl.insertBefore(cloneEl, dragEl);
			cloneEl.state = state;
		}
	}


	function _closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx) {
		if (el) {
			ctx = ctx || document;
			selector = selector.split('.');

			var tag = selector.shift().toUpperCase(),
				re = new RegExp('\\s(' + selector.join('|') + ')(?=\\s)', 'g');

			do {
				if (
					(tag === '>*' && el.parentNode === ctx) || (
						(tag === '' || el.nodeName.toUpperCase() == tag) &&
						(!selector.length || ((' ' + el.className + ' ').match(re) || []).length == selector.length)
					)
				) {
					return el;
				}
			}
			while (el !== ctx && (el = el.parentNode));
		}

		return null;
	}


	function _globalDragOver(/**Event*/evt) {
		if (evt.dataTransfer) {
			evt.dataTransfer.dropEffect = 'move';
		}
		evt.preventDefault();
	}


	function _on(el, event, fn) {
		el.addEventListener(event, fn, false);
	}


	function _off(el, event, fn) {
		el.removeEventListener(event, fn, false);
	}


	function _toggleClass(el, name, state) {
		if (el) {
			if (el.classList) {
				el.classList[state ? 'add' : 'remove'](name);
			}
			else {
				var className = (' ' + el.className + ' ').replace(RSPACE, ' ').replace(' ' + name + ' ', ' ');
				el.className = (className + (state ? ' ' + name : '')).replace(RSPACE, ' ');
			}
		}
	}


	function _css(el, prop, val) {
		var style = el && el.style;

		if (style) {
			if (val === void 0) {
				if (document.defaultView && document.defaultView.getComputedStyle) {
					val = document.defaultView.getComputedStyle(el, '');
				}
				else if (el.currentStyle) {
					val = el.currentStyle;
				}

				return prop === void 0 ? val : val[prop];
			}
			else {
				if (!(prop in style)) {
					prop = '-webkit-' + prop;
				}

				style[prop] = val + (typeof val === 'string' ? '' : 'px');
			}
		}
	}


	function _find(ctx, tagName, iterator) {
		if (ctx) {
			var list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;

			if (iterator) {
				for (; i < n; i++) {
					iterator(list[i], i);
				}
			}

			return list;
		}

		return [];
	}



	function _dispatchEvent(sortable, rootEl, name, targetEl, fromEl, startIndex, newIndex) {
		var evt = document.createEvent('Event'),
			options = (sortable || rootEl[expando]).options,
			onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);

		evt.initEvent(name, true, true);

		evt.to = rootEl;
		evt.from = fromEl || rootEl;
		evt.item = targetEl || rootEl;
		evt.clone = cloneEl;

		evt.oldIndex = startIndex;
		evt.newIndex = newIndex;

		rootEl.dispatchEvent(evt);

		if (options[onName]) {
			options[onName].call(sortable, evt);
		}
	}


	function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect) {
		var evt,
			sortable = fromEl[expando],
			onMoveFn = sortable.options.onMove,
			retVal;

		evt = document.createEvent('Event');
		evt.initEvent('move', true, true);

		evt.to = toEl;
		evt.from = fromEl;
		evt.dragged = dragEl;
		evt.draggedRect = dragRect;
		evt.related = targetEl || toEl;
		evt.relatedRect = targetRect || toEl.getBoundingClientRect();

		fromEl.dispatchEvent(evt);

		if (onMoveFn) {
			retVal = onMoveFn.call(sortable, evt);
		}

		return retVal;
	}


	function _disableDraggable(el) {
		el.draggable = false;
	}


	function _unsilent() {
		_silent = false;
	}


	/** @returns {HTMLElement|false} */
	function _ghostIsLast(el, evt) {
		var lastEl = el.lastElementChild,
				rect = lastEl.getBoundingClientRect();

		return ((evt.clientY - (rect.top + rect.height) > 5) || (evt.clientX - (rect.right + rect.width) > 5)) && lastEl; // min delta
	}


	/**
	 * Generate id
	 * @param   {HTMLElement} el
	 * @returns {String}
	 * @private
	 */
	function _generateId(el) {
		var str = el.tagName + el.className + el.src + el.href + el.textContent,
			i = str.length,
			sum = 0;

		while (i--) {
			sum += str.charCodeAt(i);
		}

		return sum.toString(36);
	}

	/**
	 * Returns the index of an element within its parent
	 * @param  {HTMLElement} el
	 * @return {number}
	 */
	function _index(el) {
		var index = 0;

		if (!el || !el.parentNode) {
			return -1;
		}

		while (el && (el = el.previousElementSibling)) {
			if (el.nodeName.toUpperCase() !== 'TEMPLATE') {
				index++;
			}
		}

		return index;
	}

	function _throttle(callback, ms) {
		var args, _this;

		return function () {
			if (args === void 0) {
				args = arguments;
				_this = this;

				setTimeout(function () {
					if (args.length === 1) {
						callback.call(_this, args[0]);
					} else {
						callback.apply(_this, args);
					}

					args = void 0;
				}, ms);
			}
		};
	}

	function _extend(dst, src) {
		if (dst && src) {
			for (var key in src) {
				if (src.hasOwnProperty(key)) {
					dst[key] = src[key];
				}
			}
		}

		return dst;
	}


	// Export utils
	Sortable.utils = {
		on: _on,
		off: _off,
		css: _css,
		find: _find,
		is: function (el, selector) {
			return !!_closest(el, selector, el);
		},
		extend: _extend,
		throttle: _throttle,
		closest: _closest,
		toggleClass: _toggleClass,
		index: _index
	};


	/**
	 * Create sortable instance
	 * @param {HTMLElement}  el
	 * @param {Object}      [options]
	 */
	Sortable.create = function (el, options) {
		return new Sortable(el, options);
	};


	// Export
	Sortable.version = '1.3.0';
	return Sortable;
});

},{}],197:[function(require,module,exports){
/*! tether-drop 1.4.1 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(["tether"], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('tether'));
  } else {
    root.Drop = factory(root.Tether);
  }
}(this, function(Tether) {

/* global Tether */
'use strict';

var _bind = Function.prototype.bind;

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var _Tether$Utils = Tether.Utils;
var extend = _Tether$Utils.extend;
var addClass = _Tether$Utils.addClass;
var removeClass = _Tether$Utils.removeClass;
var hasClass = _Tether$Utils.hasClass;
var Evented = _Tether$Utils.Evented;

function sortAttach(str) {
  var _str$split = str.split(' ');

  var _str$split2 = _slicedToArray(_str$split, 2);

  var first = _str$split2[0];
  var second = _str$split2[1];

  if (['left', 'right'].indexOf(first) >= 0) {
    var _ref = [second, first];
    first = _ref[0];
    second = _ref[1];
  }
  return [first, second].join(' ');
}

function removeFromArray(arr, item) {
  var index = undefined;
  var results = [];
  while ((index = arr.indexOf(item)) !== -1) {
    results.push(arr.splice(index, 1));
  }
  return results;
}

var clickEvents = ['click'];
if ('ontouchstart' in document.documentElement) {
  clickEvents.push('touchstart');
}

var transitionEndEvents = {
  'WebkitTransition': 'webkitTransitionEnd',
  'MozTransition': 'transitionend',
  'OTransition': 'otransitionend',
  'transition': 'transitionend'
};

var transitionEndEvent = '';
for (var _name in transitionEndEvents) {
  if (({}).hasOwnProperty.call(transitionEndEvents, _name)) {
    var tempEl = document.createElement('p');
    if (typeof tempEl.style[_name] !== 'undefined') {
      transitionEndEvent = transitionEndEvents[_name];
    }
  }
}

var MIRROR_ATTACH = {
  left: 'right',
  right: 'left',
  top: 'bottom',
  bottom: 'top',
  middle: 'middle',
  center: 'center'
};

var allDrops = {};

// Drop can be included in external libraries.  Calling createContext gives you a fresh
// copy of drop which won't interact with other copies on the page (beyond calling the document events).

function createContext() {
  var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var drop = function drop() {
    for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    return new (_bind.apply(DropInstance, [null].concat(args)))();
  };

  extend(drop, {
    createContext: createContext,
    drops: [],
    defaults: {}
  });

  var defaultOptions = {
    classPrefix: 'drop',
    defaults: {
      position: 'bottom left',
      openOn: 'click',
      beforeClose: null,
      constrainToScrollParent: true,
      constrainToWindow: true,
      classes: '',
      remove: false,
      openDelay: 0,
      closeDelay: 50,
      // inherited from openDelay and closeDelay if not explicitly defined
      focusDelay: null,
      blurDelay: null,
      hoverOpenDelay: null,
      hoverCloseDelay: null,
      tetherOptions: {}
    }
  };

  extend(drop, defaultOptions, options);
  extend(drop.defaults, defaultOptions.defaults, options.defaults);

  if (typeof allDrops[drop.classPrefix] === 'undefined') {
    allDrops[drop.classPrefix] = [];
  }

  drop.updateBodyClasses = function () {
    // There is only one body, so despite the context concept, we still iterate through all
    // drops which share our classPrefix.

    var anyOpen = false;
    var drops = allDrops[drop.classPrefix];
    var len = drops.length;
    for (var i = 0; i < len; ++i) {
      if (drops[i].isOpened()) {
        anyOpen = true;
        break;
      }
    }

    if (anyOpen) {
      addClass(document.body, drop.classPrefix + '-open');
    } else {
      removeClass(document.body, drop.classPrefix + '-open');
    }
  };

  var DropInstance = (function (_Evented) {
    _inherits(DropInstance, _Evented);

    function DropInstance(opts) {
      _classCallCheck(this, DropInstance);

      _get(Object.getPrototypeOf(DropInstance.prototype), 'constructor', this).call(this);
      this.options = extend({}, drop.defaults, opts);
      this.target = this.options.target;

      if (typeof this.target === 'undefined') {
        throw new Error('Drop Error: You must provide a target.');
      }

      var dataPrefix = 'data-' + drop.classPrefix;

      var contentAttr = this.target.getAttribute(dataPrefix);
      if (contentAttr && this.options.content == null) {
        this.options.content = contentAttr;
      }

      var attrsOverride = ['position', 'openOn'];
      for (var i = 0; i < attrsOverride.length; ++i) {

        var override = this.target.getAttribute(dataPrefix + '-' + attrsOverride[i]);
        if (override && this.options[attrsOverride[i]] == null) {
          this.options[attrsOverride[i]] = override;
        }
      }

      if (this.options.classes && this.options.addTargetClasses !== false) {
        addClass(this.target, this.options.classes);
      }

      drop.drops.push(this);
      allDrops[drop.classPrefix].push(this);

      this._boundEvents = [];
      this.bindMethods();
      this.setupElements();
      this.setupEvents();
      this.setupTether();
    }

    _createClass(DropInstance, [{
      key: '_on',
      value: function _on(element, event, handler) {
        this._boundEvents.push({ element: element, event: event, handler: handler });
        element.addEventListener(event, handler);
      }
    }, {
      key: 'bindMethods',
      value: function bindMethods() {
        this.transitionEndHandler = this._transitionEndHandler.bind(this);
      }
    }, {
      key: 'setupElements',
      value: function setupElements() {
        var _this = this;

        this.drop = document.createElement('div');
        addClass(this.drop, drop.classPrefix);

        if (this.options.classes) {
          addClass(this.drop, this.options.classes);
        }

        this.content = document.createElement('div');
        addClass(this.content, drop.classPrefix + '-content');

        if (typeof this.options.content === 'function') {
          var generateAndSetContent = function generateAndSetContent() {
            // content function might return a string or an element
            var contentElementOrHTML = _this.options.content.call(_this, _this);

            if (typeof contentElementOrHTML === 'string') {
              _this.content.innerHTML = contentElementOrHTML;
            } else if (typeof contentElementOrHTML === 'object') {
              _this.content.innerHTML = '';
              _this.content.appendChild(contentElementOrHTML);
            } else {
              throw new Error('Drop Error: Content function should return a string or HTMLElement.');
            }
          };

          generateAndSetContent();
          this.on('open', generateAndSetContent.bind(this));
        } else if (typeof this.options.content === 'object') {
          this.content.appendChild(this.options.content);
        } else {
          this.content.innerHTML = this.options.content;
        }

        this.drop.appendChild(this.content);
      }
    }, {
      key: 'setupTether',
      value: function setupTether() {
        // Tether expects two attachment points, one in the target element, one in the
        // drop.  We use a single one, and use the order as well, to allow us to put
        // the drop on either side of any of the four corners.  This magic converts between
        // the two:
        var dropAttach = this.options.position.split(' ');
        dropAttach[0] = MIRROR_ATTACH[dropAttach[0]];
        dropAttach = dropAttach.join(' ');

        var constraints = [];
        if (this.options.constrainToScrollParent) {
          constraints.push({
            to: 'scrollParent',
            pin: 'top, bottom',
            attachment: 'together none'
          });
        } else {
          // To get 'out of bounds' classes
          constraints.push({
            to: 'scrollParent'
          });
        }

        if (this.options.constrainToWindow !== false) {
          constraints.push({
            to: 'window',
            attachment: 'together'
          });
        } else {
          // To get 'out of bounds' classes
          constraints.push({
            to: 'window'
          });
        }

        var opts = {
          element: this.drop,
          target: this.target,
          attachment: sortAttach(dropAttach),
          targetAttachment: sortAttach(this.options.position),
          classPrefix: drop.classPrefix,
          offset: '0 0',
          targetOffset: '0 0',
          enabled: false,
          constraints: constraints,
          addTargetClasses: this.options.addTargetClasses
        };

        if (this.options.tetherOptions !== false) {
          this.tether = new Tether(extend({}, opts, this.options.tetherOptions));
        }
      }
    }, {
      key: 'setupEvents',
      value: function setupEvents() {
        var _this2 = this;

        if (!this.options.openOn) {
          return;
        }

        if (this.options.openOn === 'always') {
          setTimeout(this.open.bind(this));
          return;
        }

        var events = this.options.openOn.split(' ');

        if (events.indexOf('click') >= 0) {
          var openHandler = function openHandler(event) {
            _this2.toggle(event);
            event.preventDefault();
          };

          var closeHandler = function closeHandler(event) {
            if (!_this2.isOpened()) {
              return;
            }

            // Clicking inside dropdown
            if (event.target === _this2.drop || _this2.drop.contains(event.target)) {
              return;
            }

            // Clicking target
            if (event.target === _this2.target || _this2.target.contains(event.target)) {
              return;
            }

            _this2.close(event);
          };

          for (var i = 0; i < clickEvents.length; ++i) {
            var clickEvent = clickEvents[i];
            this._on(this.target, clickEvent, openHandler);
            this._on(document, clickEvent, closeHandler);
          }
        }

        var inTimeout = null;
        var outTimeout = null;

        var inHandler = function inHandler(event) {
          if (outTimeout !== null) {
            clearTimeout(outTimeout);
          } else {
            inTimeout = setTimeout(function () {
              _this2.open(event);
              inTimeout = null;
            }, (event.type === 'focus' ? _this2.options.focusDelay : _this2.options.hoverOpenDelay) || _this2.options.openDelay);
          }
        };

        var outHandler = function outHandler(event) {
          if (inTimeout !== null) {
            clearTimeout(inTimeout);
          } else {
            outTimeout = setTimeout(function () {
              _this2.close(event);
              outTimeout = null;
            }, (event.type === 'blur' ? _this2.options.blurDelay : _this2.options.hoverCloseDelay) || _this2.options.closeDelay);
          }
        };

        if (events.indexOf('hover') >= 0) {
          this._on(this.target, 'mouseover', inHandler);
          this._on(this.drop, 'mouseover', inHandler);
          this._on(this.target, 'mouseout', outHandler);
          this._on(this.drop, 'mouseout', outHandler);
        }

        if (events.indexOf('focus') >= 0) {
          this._on(this.target, 'focus', inHandler);
          this._on(this.drop, 'focus', inHandler);
          this._on(this.target, 'blur', outHandler);
          this._on(this.drop, 'blur', outHandler);
        }
      }
    }, {
      key: 'isOpened',
      value: function isOpened() {
        if (this.drop) {
          return hasClass(this.drop, drop.classPrefix + '-open');
        }
      }
    }, {
      key: 'toggle',
      value: function toggle(event) {
        if (this.isOpened()) {
          this.close(event);
        } else {
          this.open(event);
        }
      }
    }, {
      key: 'open',
      value: function open(event) {
        var _this3 = this;

        /* eslint no-unused-vars: 0 */
        if (this.isOpened()) {
          return;
        }

        if (!this.drop.parentNode) {
          document.body.appendChild(this.drop);
        }

        if (typeof this.tether !== 'undefined') {
          this.tether.enable();
        }

        addClass(this.drop, drop.classPrefix + '-open');
        addClass(this.drop, drop.classPrefix + '-open-transitionend');

        setTimeout(function () {
          if (_this3.drop) {
            addClass(_this3.drop, drop.classPrefix + '-after-open');
          }
        });

        if (typeof this.tether !== 'undefined') {
          this.tether.position();
        }

        this.trigger('open');

        drop.updateBodyClasses();
      }
    }, {
      key: '_transitionEndHandler',
      value: function _transitionEndHandler(e) {
        if (e.target !== e.currentTarget) {
          return;
        }

        if (!hasClass(this.drop, drop.classPrefix + '-open')) {
          removeClass(this.drop, drop.classPrefix + '-open-transitionend');
        }
        this.drop.removeEventListener(transitionEndEvent, this.transitionEndHandler);
      }
    }, {
      key: 'beforeCloseHandler',
      value: function beforeCloseHandler(event) {
        var shouldClose = true;

        if (!this.isClosing && typeof this.options.beforeClose === 'function') {
          this.isClosing = true;
          shouldClose = this.options.beforeClose(event, this) !== false;
        }

        this.isClosing = false;

        return shouldClose;
      }
    }, {
      key: 'close',
      value: function close(event) {
        if (!this.isOpened()) {
          return;
        }

        if (!this.beforeCloseHandler(event)) {
          return;
        }

        removeClass(this.drop, drop.classPrefix + '-open');
        removeClass(this.drop, drop.classPrefix + '-after-open');

        this.drop.addEventListener(transitionEndEvent, this.transitionEndHandler);

        this.trigger('close');

        if (typeof this.tether !== 'undefined') {
          this.tether.disable();
        }

        drop.updateBodyClasses();

        if (this.options.remove) {
          this.remove(event);
        }
      }
    }, {
      key: 'remove',
      value: function remove(event) {
        this.close(event);
        if (this.drop.parentNode) {
          this.drop.parentNode.removeChild(this.drop);
        }
      }
    }, {
      key: 'position',
      value: function position() {
        if (this.isOpened() && typeof this.tether !== 'undefined') {
          this.tether.position();
        }
      }
    }, {
      key: 'destroy',
      value: function destroy() {
        this.remove();

        if (typeof this.tether !== 'undefined') {
          this.tether.destroy();
        }

        for (var i = 0; i < this._boundEvents.length; ++i) {
          var _boundEvents$i = this._boundEvents[i];
          var element = _boundEvents$i.element;
          var _event = _boundEvents$i.event;
          var handler = _boundEvents$i.handler;

          element.removeEventListener(_event, handler);
        }

        this._boundEvents = [];

        this.tether = null;
        this.drop = null;
        this.content = null;
        this.target = null;

        removeFromArray(allDrops[drop.classPrefix], this);
        removeFromArray(drop.drops, this);
      }
    }]);

    return DropInstance;
  })(Evented);

  return drop;
}

var Drop = createContext();

document.addEventListener('DOMContentLoaded', function () {
  Drop.updateBodyClasses();
});
return Drop;

}));

},{"tether":198}],198:[function(require,module,exports){
/*! tether 1.2.0 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require, exports, module);
  } else {
    root.Tether = factory();
  }
}(this, function(require, exports, module) {

'use strict';

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

var TetherBase = undefined;
if (typeof TetherBase === 'undefined') {
  TetherBase = { modules: [] };
}

function getScrollParent(el) {
  // In firefox if the el is inside an iframe with display: none; window.getComputedStyle() will return null;
  // https://bugzilla.mozilla.org/show_bug.cgi?id=548397
  var computedStyle = getComputedStyle(el) || {};
  var position = computedStyle.position;

  if (position === 'fixed') {
    return el;
  }

  var parent = el;
  while (parent = parent.parentNode) {
    var style = undefined;
    try {
      style = getComputedStyle(parent);
    } catch (err) {}

    if (typeof style === 'undefined' || style === null) {
      return parent;
    }

    var _style = style;
    var overflow = _style.overflow;
    var overflowX = _style.overflowX;
    var overflowY = _style.overflowY;

    if (/(auto|scroll)/.test(overflow + overflowY + overflowX)) {
      if (position !== 'absolute' || ['relative', 'absolute', 'fixed'].indexOf(style.position) >= 0) {
        return parent;
      }
    }
  }

  return document.body;
}

var uniqueId = (function () {
  var id = 0;
  return function () {
    return ++id;
  };
})();

var zeroPosCache = {};
var getOrigin = function getOrigin(doc) {
  // getBoundingClientRect is unfortunately too accurate.  It introduces a pixel or two of
  // jitter as the user scrolls that messes with our ability to detect if two positions
  // are equivilant or not.  We place an element at the top left of the page that will
  // get the same jitter, so we can cancel the two out.
  var node = doc._tetherZeroElement;
  if (typeof node === 'undefined') {
    node = doc.createElement('div');
    node.setAttribute('data-tether-id', uniqueId());
    extend(node.style, {
      top: 0,
      left: 0,
      position: 'absolute'
    });

    doc.body.appendChild(node);

    doc._tetherZeroElement = node;
  }

  var id = node.getAttribute('data-tether-id');
  if (typeof zeroPosCache[id] === 'undefined') {
    zeroPosCache[id] = {};

    var rect = node.getBoundingClientRect();
    for (var k in rect) {
      // Can't use extend, as on IE9, elements don't resolve to be hasOwnProperty
      zeroPosCache[id][k] = rect[k];
    }

    // Clear the cache when this position call is done
    defer(function () {
      delete zeroPosCache[id];
    });
  }

  return zeroPosCache[id];
};

function getBounds(el) {
  var doc = undefined;
  if (el === document) {
    doc = document;
    el = document.documentElement;
  } else {
    doc = el.ownerDocument;
  }

  var docEl = doc.documentElement;

  var box = {};
  // The original object returned by getBoundingClientRect is immutable, so we clone it
  // We can't use extend because the properties are not considered part of the object by hasOwnProperty in IE9
  var rect = el.getBoundingClientRect();
  for (var k in rect) {
    box[k] = rect[k];
  }

  var origin = getOrigin(doc);

  box.top -= origin.top;
  box.left -= origin.left;

  if (typeof box.width === 'undefined') {
    box.width = document.body.scrollWidth - box.left - box.right;
  }
  if (typeof box.height === 'undefined') {
    box.height = document.body.scrollHeight - box.top - box.bottom;
  }

  box.top = box.top - docEl.clientTop;
  box.left = box.left - docEl.clientLeft;
  box.right = doc.body.clientWidth - box.width - box.left;
  box.bottom = doc.body.clientHeight - box.height - box.top;

  return box;
}

function getOffsetParent(el) {
  return el.offsetParent || document.documentElement;
}

function getScrollBarSize() {
  var inner = document.createElement('div');
  inner.style.width = '100%';
  inner.style.height = '200px';

  var outer = document.createElement('div');
  extend(outer.style, {
    position: 'absolute',
    top: 0,
    left: 0,
    pointerEvents: 'none',
    visibility: 'hidden',
    width: '200px',
    height: '150px',
    overflow: 'hidden'
  });

  outer.appendChild(inner);

  document.body.appendChild(outer);

  var widthContained = inner.offsetWidth;
  outer.style.overflow = 'scroll';
  var widthScroll = inner.offsetWidth;

  if (widthContained === widthScroll) {
    widthScroll = outer.clientWidth;
  }

  document.body.removeChild(outer);

  var width = widthContained - widthScroll;

  return { width: width, height: width };
}

function extend() {
  var out = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var args = [];

  Array.prototype.push.apply(args, arguments);

  args.slice(1).forEach(function (obj) {
    if (obj) {
      for (var key in obj) {
        if (({}).hasOwnProperty.call(obj, key)) {
          out[key] = obj[key];
        }
      }
    }
  });

  return out;
}

function removeClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    name.split(' ').forEach(function (cls) {
      if (cls.trim()) {
        el.classList.remove(cls);
      }
    });
  } else {
    var regex = new RegExp('(^| )' + name.split(' ').join('|') + '( |$)', 'gi');
    var className = getClassName(el).replace(regex, ' ');
    setClassName(el, className);
  }
}

function addClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    name.split(' ').forEach(function (cls) {
      if (cls.trim()) {
        el.classList.add(cls);
      }
    });
  } else {
    removeClass(el, name);
    var cls = getClassName(el) + (' ' + name);
    setClassName(el, cls);
  }
}

function hasClass(el, name) {
  if (typeof el.classList !== 'undefined') {
    return el.classList.contains(name);
  }
  var className = getClassName(el);
  return new RegExp('(^| )' + name + '( |$)', 'gi').test(className);
}

function getClassName(el) {
  if (el.className instanceof SVGAnimatedString) {
    return el.className.baseVal;
  }
  return el.className;
}

function setClassName(el, className) {
  el.setAttribute('class', className);
}

function updateClasses(el, add, all) {
  // Of the set of 'all' classes, we need the 'add' classes, and only the
  // 'add' classes to be set.
  all.forEach(function (cls) {
    if (add.indexOf(cls) === -1 && hasClass(el, cls)) {
      removeClass(el, cls);
    }
  });

  add.forEach(function (cls) {
    if (!hasClass(el, cls)) {
      addClass(el, cls);
    }
  });
}

var deferred = [];

var defer = function defer(fn) {
  deferred.push(fn);
};

var flush = function flush() {
  var fn = undefined;
  while (fn = deferred.pop()) {
    fn();
  }
};

var Evented = (function () {
  function Evented() {
    _classCallCheck(this, Evented);
  }

  _createClass(Evented, [{
    key: 'on',
    value: function on(event, handler, ctx) {
      var once = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];

      if (typeof this.bindings === 'undefined') {
        this.bindings = {};
      }
      if (typeof this.bindings[event] === 'undefined') {
        this.bindings[event] = [];
      }
      this.bindings[event].push({ handler: handler, ctx: ctx, once: once });
    }
  }, {
    key: 'once',
    value: function once(event, handler, ctx) {
      this.on(event, handler, ctx, true);
    }
  }, {
    key: 'off',
    value: function off(event, handler) {
      if (typeof this.bindings !== 'undefined' && typeof this.bindings[event] !== 'undefined') {
        return;
      }

      if (typeof handler === 'undefined') {
        delete this.bindings[event];
      } else {
        var i = 0;
        while (i < this.bindings[event].length) {
          if (this.bindings[event][i].handler === handler) {
            this.bindings[event].splice(i, 1);
          } else {
            ++i;
          }
        }
      }
    }
  }, {
    key: 'trigger',
    value: function trigger(event) {
      if (typeof this.bindings !== 'undefined' && this.bindings[event]) {
        var i = 0;

        for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
          args[_key - 1] = arguments[_key];
        }

        while (i < this.bindings[event].length) {
          var _bindings$event$i = this.bindings[event][i];
          var handler = _bindings$event$i.handler;
          var ctx = _bindings$event$i.ctx;
          var once = _bindings$event$i.once;

          var context = ctx;
          if (typeof context === 'undefined') {
            context = this;
          }

          handler.apply(context, args);

          if (once) {
            this.bindings[event].splice(i, 1);
          } else {
            ++i;
          }
        }
      }
    }
  }]);

  return Evented;
})();

TetherBase.Utils = {
  getScrollParent: getScrollParent,
  getBounds: getBounds,
  getOffsetParent: getOffsetParent,
  extend: extend,
  addClass: addClass,
  removeClass: removeClass,
  hasClass: hasClass,
  updateClasses: updateClasses,
  defer: defer,
  flush: flush,
  uniqueId: uniqueId,
  Evented: Evented,
  getScrollBarSize: getScrollBarSize
};
/* globals TetherBase, performance */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

if (typeof TetherBase === 'undefined') {
  throw new Error('You must include the utils.js file before tether.js');
}

var _TetherBase$Utils = TetherBase.Utils;
var getScrollParent = _TetherBase$Utils.getScrollParent;
var getBounds = _TetherBase$Utils.getBounds;
var getOffsetParent = _TetherBase$Utils.getOffsetParent;
var extend = _TetherBase$Utils.extend;
var addClass = _TetherBase$Utils.addClass;
var removeClass = _TetherBase$Utils.removeClass;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;
var flush = _TetherBase$Utils.flush;
var getScrollBarSize = _TetherBase$Utils.getScrollBarSize;

function within(a, b) {
  var diff = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];

  return a + diff >= b && b >= a - diff;
}

var transformKey = (function () {
  if (typeof document === 'undefined') {
    return '';
  }
  var el = document.createElement('div');

  var transforms = ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform'];
  for (var i = 0; i < transforms.length; ++i) {
    var key = transforms[i];
    if (el.style[key] !== undefined) {
      return key;
    }
  }
})();

var tethers = [];

var position = function position() {
  tethers.forEach(function (tether) {
    tether.position(false);
  });
  flush();
};

function now() {
  if (typeof performance !== 'undefined' && typeof performance.now !== 'undefined') {
    return performance.now();
  }
  return +new Date();
}

(function () {
  var lastCall = null;
  var lastDuration = null;
  var pendingTimeout = null;

  var tick = function tick() {
    if (typeof lastDuration !== 'undefined' && lastDuration > 16) {
      // We voluntarily throttle ourselves if we can't manage 60fps
      lastDuration = Math.min(lastDuration - 16, 250);

      // Just in case this is the last event, remember to position just once more
      pendingTimeout = setTimeout(tick, 250);
      return;
    }

    if (typeof lastCall !== 'undefined' && now() - lastCall < 10) {
      // Some browsers call events a little too frequently, refuse to run more than is reasonable
      return;
    }

    if (typeof pendingTimeout !== 'undefined') {
      clearTimeout(pendingTimeout);
      pendingTimeout = null;
    }

    lastCall = now();
    position();
    lastDuration = now() - lastCall;
  };

  if (typeof window !== 'undefined') {
    ['resize', 'scroll', 'touchmove'].forEach(function (event) {
      window.addEventListener(event, tick);
    });
  }
})();

var MIRROR_LR = {
  center: 'center',
  left: 'right',
  right: 'left'
};

var MIRROR_TB = {
  middle: 'middle',
  top: 'bottom',
  bottom: 'top'
};

var OFFSET_MAP = {
  top: 0,
  left: 0,
  middle: '50%',
  center: '50%',
  bottom: '100%',
  right: '100%'
};

var autoToFixedAttachment = function autoToFixedAttachment(attachment, relativeToAttachment) {
  var left = attachment.left;
  var top = attachment.top;

  if (left === 'auto') {
    left = MIRROR_LR[relativeToAttachment.left];
  }

  if (top === 'auto') {
    top = MIRROR_TB[relativeToAttachment.top];
  }

  return { left: left, top: top };
};

var attachmentToOffset = function attachmentToOffset(attachment) {
  var left = attachment.left;
  var top = attachment.top;

  if (typeof OFFSET_MAP[attachment.left] !== 'undefined') {
    left = OFFSET_MAP[attachment.left];
  }

  if (typeof OFFSET_MAP[attachment.top] !== 'undefined') {
    top = OFFSET_MAP[attachment.top];
  }

  return { left: left, top: top };
};

function addOffset() {
  var out = { top: 0, left: 0 };

  for (var _len = arguments.length, offsets = Array(_len), _key = 0; _key < _len; _key++) {
    offsets[_key] = arguments[_key];
  }

  offsets.forEach(function (_ref) {
    var top = _ref.top;
    var left = _ref.left;

    if (typeof top === 'string') {
      top = parseFloat(top, 10);
    }
    if (typeof left === 'string') {
      left = parseFloat(left, 10);
    }

    out.top += top;
    out.left += left;
  });

  return out;
}

function offsetToPx(offset, size) {
  if (typeof offset.left === 'string' && offset.left.indexOf('%') !== -1) {
    offset.left = parseFloat(offset.left, 10) / 100 * size.width;
  }
  if (typeof offset.top === 'string' && offset.top.indexOf('%') !== -1) {
    offset.top = parseFloat(offset.top, 10) / 100 * size.height;
  }

  return offset;
}

var parseOffset = function parseOffset(value) {
  var _value$split = value.split(' ');

  var _value$split2 = _slicedToArray(_value$split, 2);

  var top = _value$split2[0];
  var left = _value$split2[1];

  return { top: top, left: left };
};
var parseAttachment = parseOffset;

var TetherClass = (function () {
  function TetherClass(options) {
    var _this = this;

    _classCallCheck(this, TetherClass);

    this.position = this.position.bind(this);

    tethers.push(this);

    this.history = [];

    this.setOptions(options, false);

    TetherBase.modules.forEach(function (module) {
      if (typeof module.initialize !== 'undefined') {
        module.initialize.call(_this);
      }
    });

    this.position();
  }

  _createClass(TetherClass, [{
    key: 'getClass',
    value: function getClass() {
      var key = arguments.length <= 0 || arguments[0] === undefined ? '' : arguments[0];
      var classes = this.options.classes;

      if (typeof classes !== 'undefined' && classes[key]) {
        return this.options.classes[key];
      } else if (this.options.classPrefix) {
        return this.options.classPrefix + '-' + key;
      } else {
        return key;
      }
    }
  }, {
    key: 'setOptions',
    value: function setOptions(options) {
      var _this2 = this;

      var pos = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1];

      var defaults = {
        offset: '0 0',
        targetOffset: '0 0',
        targetAttachment: 'auto auto',
        classPrefix: 'tether'
      };

      this.options = extend(defaults, options);

      var _options = this.options;
      var element = _options.element;
      var target = _options.target;
      var targetModifier = _options.targetModifier;

      this.element = element;
      this.target = target;
      this.targetModifier = targetModifier;

      if (this.target === 'viewport') {
        this.target = document.body;
        this.targetModifier = 'visible';
      } else if (this.target === 'scroll-handle') {
        this.target = document.body;
        this.targetModifier = 'scroll-handle';
      }

      ['element', 'target'].forEach(function (key) {
        if (typeof _this2[key] === 'undefined') {
          throw new Error('Tether Error: Both element and target must be defined');
        }

        if (typeof _this2[key].jquery !== 'undefined') {
          _this2[key] = _this2[key][0];
        } else if (typeof _this2[key] === 'string') {
          _this2[key] = document.querySelector(_this2[key]);
        }
      });

      addClass(this.element, this.getClass('element'));
      if (!(this.options.addTargetClasses === false)) {
        addClass(this.target, this.getClass('target'));
      }

      if (!this.options.attachment) {
        throw new Error('Tether Error: You must provide an attachment');
      }

      this.targetAttachment = parseAttachment(this.options.targetAttachment);
      this.attachment = parseAttachment(this.options.attachment);
      this.offset = parseOffset(this.options.offset);
      this.targetOffset = parseOffset(this.options.targetOffset);

      if (typeof this.scrollParent !== 'undefined') {
        this.disable();
      }

      if (this.targetModifier === 'scroll-handle') {
        this.scrollParent = this.target;
      } else {
        this.scrollParent = getScrollParent(this.target);
      }

      if (!(this.options.enabled === false)) {
        this.enable(pos);
      }
    }
  }, {
    key: 'getTargetBounds',
    value: function getTargetBounds() {
      if (typeof this.targetModifier !== 'undefined') {
        if (this.targetModifier === 'visible') {
          if (this.target === document.body) {
            return { top: pageYOffset, left: pageXOffset, height: innerHeight, width: innerWidth };
          } else {
            var bounds = getBounds(this.target);

            var out = {
              height: bounds.height,
              width: bounds.width,
              top: bounds.top,
              left: bounds.left
            };

            out.height = Math.min(out.height, bounds.height - (pageYOffset - bounds.top));
            out.height = Math.min(out.height, bounds.height - (bounds.top + bounds.height - (pageYOffset + innerHeight)));
            out.height = Math.min(innerHeight, out.height);
            out.height -= 2;

            out.width = Math.min(out.width, bounds.width - (pageXOffset - bounds.left));
            out.width = Math.min(out.width, bounds.width - (bounds.left + bounds.width - (pageXOffset + innerWidth)));
            out.width = Math.min(innerWidth, out.width);
            out.width -= 2;

            if (out.top < pageYOffset) {
              out.top = pageYOffset;
            }
            if (out.left < pageXOffset) {
              out.left = pageXOffset;
            }

            return out;
          }
        } else if (this.targetModifier === 'scroll-handle') {
          var bounds = undefined;
          var target = this.target;
          if (target === document.body) {
            target = document.documentElement;

            bounds = {
              left: pageXOffset,
              top: pageYOffset,
              height: innerHeight,
              width: innerWidth
            };
          } else {
            bounds = getBounds(target);
          }

          var style = getComputedStyle(target);

          var hasBottomScroll = target.scrollWidth > target.clientWidth || [style.overflow, style.overflowX].indexOf('scroll') >= 0 || this.target !== document.body;

          var scrollBottom = 0;
          if (hasBottomScroll) {
            scrollBottom = 15;
          }

          var height = bounds.height - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth) - scrollBottom;

          var out = {
            width: 15,
            height: height * 0.975 * (height / target.scrollHeight),
            left: bounds.left + bounds.width - parseFloat(style.borderLeftWidth) - 15
          };

          var fitAdj = 0;
          if (height < 408 && this.target === document.body) {
            fitAdj = -0.00011 * Math.pow(height, 2) - 0.00727 * height + 22.58;
          }

          if (this.target !== document.body) {
            out.height = Math.max(out.height, 24);
          }

          var scrollPercentage = this.target.scrollTop / (target.scrollHeight - height);
          out.top = scrollPercentage * (height - out.height - fitAdj) + bounds.top + parseFloat(style.borderTopWidth);

          if (this.target === document.body) {
            out.height = Math.max(out.height, 24);
          }

          return out;
        }
      } else {
        return getBounds(this.target);
      }
    }
  }, {
    key: 'clearCache',
    value: function clearCache() {
      this._cache = {};
    }
  }, {
    key: 'cache',
    value: function cache(k, getter) {
      // More than one module will often need the same DOM info, so
      // we keep a cache which is cleared on each position call
      if (typeof this._cache === 'undefined') {
        this._cache = {};
      }

      if (typeof this._cache[k] === 'undefined') {
        this._cache[k] = getter.call(this);
      }

      return this._cache[k];
    }
  }, {
    key: 'enable',
    value: function enable() {
      var pos = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];

      if (!(this.options.addTargetClasses === false)) {
        addClass(this.target, this.getClass('enabled'));
      }
      addClass(this.element, this.getClass('enabled'));
      this.enabled = true;

      if (this.scrollParent !== document) {
        this.scrollParent.addEventListener('scroll', this.position);
      }

      if (pos) {
        this.position();
      }
    }
  }, {
    key: 'disable',
    value: function disable() {
      removeClass(this.target, this.getClass('enabled'));
      removeClass(this.element, this.getClass('enabled'));
      this.enabled = false;

      if (typeof this.scrollParent !== 'undefined') {
        this.scrollParent.removeEventListener('scroll', this.position);
      }
    }
  }, {
    key: 'destroy',
    value: function destroy() {
      var _this3 = this;

      this.disable();

      tethers.forEach(function (tether, i) {
        if (tether === _this3) {
          tethers.splice(i, 1);
          return;
        }
      });
    }
  }, {
    key: 'updateAttachClasses',
    value: function updateAttachClasses(elementAttach, targetAttach) {
      var _this4 = this;

      elementAttach = elementAttach || this.attachment;
      targetAttach = targetAttach || this.targetAttachment;
      var sides = ['left', 'top', 'bottom', 'right', 'middle', 'center'];

      if (typeof this._addAttachClasses !== 'undefined' && this._addAttachClasses.length) {
        // updateAttachClasses can be called more than once in a position call, so
        // we need to clean up after ourselves such that when the last defer gets
        // ran it doesn't add any extra classes from previous calls.
        this._addAttachClasses.splice(0, this._addAttachClasses.length);
      }

      if (typeof this._addAttachClasses === 'undefined') {
        this._addAttachClasses = [];
      }
      var add = this._addAttachClasses;

      if (elementAttach.top) {
        add.push(this.getClass('element-attached') + '-' + elementAttach.top);
      }
      if (elementAttach.left) {
        add.push(this.getClass('element-attached') + '-' + elementAttach.left);
      }
      if (targetAttach.top) {
        add.push(this.getClass('target-attached') + '-' + targetAttach.top);
      }
      if (targetAttach.left) {
        add.push(this.getClass('target-attached') + '-' + targetAttach.left);
      }

      var all = [];
      sides.forEach(function (side) {
        all.push(_this4.getClass('element-attached') + '-' + side);
        all.push(_this4.getClass('target-attached') + '-' + side);
      });

      defer(function () {
        if (!(typeof _this4._addAttachClasses !== 'undefined')) {
          return;
        }

        updateClasses(_this4.element, _this4._addAttachClasses, all);
        if (!(_this4.options.addTargetClasses === false)) {
          updateClasses(_this4.target, _this4._addAttachClasses, all);
        }

        delete _this4._addAttachClasses;
      });
    }
  }, {
    key: 'position',
    value: function position() {
      var _this5 = this;

      var flushChanges = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0];

      // flushChanges commits the changes immediately, leave true unless you are positioning multiple
      // tethers (in which case call Tether.Utils.flush yourself when you're done)

      if (!this.enabled) {
        return;
      }

      this.clearCache();

      // Turn 'auto' attachments into the appropriate corner or edge
      var targetAttachment = autoToFixedAttachment(this.targetAttachment, this.attachment);

      this.updateAttachClasses(this.attachment, targetAttachment);

      var elementPos = this.cache('element-bounds', function () {
        return getBounds(_this5.element);
      });

      var width = elementPos.width;
      var height = elementPos.height;

      if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
        var _lastSize = this.lastSize;

        // We cache the height and width to make it possible to position elements that are
        // getting hidden.
        width = _lastSize.width;
        height = _lastSize.height;
      } else {
        this.lastSize = { width: width, height: height };
      }

      var targetPos = this.cache('target-bounds', function () {
        return _this5.getTargetBounds();
      });
      var targetSize = targetPos;

      // Get an actual px offset from the attachment
      var offset = offsetToPx(attachmentToOffset(this.attachment), { width: width, height: height });
      var targetOffset = offsetToPx(attachmentToOffset(targetAttachment), targetSize);

      var manualOffset = offsetToPx(this.offset, { width: width, height: height });
      var manualTargetOffset = offsetToPx(this.targetOffset, targetSize);

      // Add the manually provided offset
      offset = addOffset(offset, manualOffset);
      targetOffset = addOffset(targetOffset, manualTargetOffset);

      // It's now our goal to make (element position + offset) == (target position + target offset)
      var left = targetPos.left + targetOffset.left - offset.left;
      var top = targetPos.top + targetOffset.top - offset.top;

      for (var i = 0; i < TetherBase.modules.length; ++i) {
        var _module2 = TetherBase.modules[i];
        var ret = _module2.position.call(this, {
          left: left,
          top: top,
          targetAttachment: targetAttachment,
          targetPos: targetPos,
          elementPos: elementPos,
          offset: offset,
          targetOffset: targetOffset,
          manualOffset: manualOffset,
          manualTargetOffset: manualTargetOffset,
          scrollbarSize: scrollbarSize,
          attachment: this.attachment
        });

        if (ret === false) {
          return false;
        } else if (typeof ret === 'undefined' || typeof ret !== 'object') {
          continue;
        } else {
          top = ret.top;
          left = ret.left;
        }
      }

      // We describe the position three different ways to give the optimizer
      // a chance to decide the best possible way to position the element
      // with the fewest repaints.
      var next = {
        // It's position relative to the page (absolute positioning when
        // the element is a child of the body)
        page: {
          top: top,
          left: left
        },

        // It's position relative to the viewport (fixed positioning)
        viewport: {
          top: top - pageYOffset,
          bottom: pageYOffset - top - height + innerHeight,
          left: left - pageXOffset,
          right: pageXOffset - left - width + innerWidth
        }
      };

      var scrollbarSize = undefined;
      if (document.body.scrollWidth > window.innerWidth) {
        scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
        next.viewport.bottom -= scrollbarSize.height;
      }

      if (document.body.scrollHeight > window.innerHeight) {
        scrollbarSize = this.cache('scrollbar-size', getScrollBarSize);
        next.viewport.right -= scrollbarSize.width;
      }

      if (['', 'static'].indexOf(document.body.style.position) === -1 || ['', 'static'].indexOf(document.body.parentElement.style.position) === -1) {
        // Absolute positioning in the body will be relative to the page, not the 'initial containing block'
        next.page.bottom = document.body.scrollHeight - top - height;
        next.page.right = document.body.scrollWidth - left - width;
      }

      if (typeof this.options.optimizations !== 'undefined' && this.options.optimizations.moveElement !== false && !(typeof this.targetModifier !== 'undefined')) {
        (function () {
          var offsetParent = _this5.cache('target-offsetparent', function () {
            return getOffsetParent(_this5.target);
          });
          var offsetPosition = _this5.cache('target-offsetparent-bounds', function () {
            return getBounds(offsetParent);
          });
          var offsetParentStyle = getComputedStyle(offsetParent);
          var offsetParentSize = offsetPosition;

          var offsetBorder = {};
          ['Top', 'Left', 'Bottom', 'Right'].forEach(function (side) {
            offsetBorder[side.toLowerCase()] = parseFloat(offsetParentStyle['border' + side + 'Width']);
          });

          offsetPosition.right = document.body.scrollWidth - offsetPosition.left - offsetParentSize.width + offsetBorder.right;
          offsetPosition.bottom = document.body.scrollHeight - offsetPosition.top - offsetParentSize.height + offsetBorder.bottom;

          if (next.page.top >= offsetPosition.top + offsetBorder.top && next.page.bottom >= offsetPosition.bottom) {
            if (next.page.left >= offsetPosition.left + offsetBorder.left && next.page.right >= offsetPosition.right) {
              // We're within the visible part of the target's scroll parent
              var scrollTop = offsetParent.scrollTop;
              var scrollLeft = offsetParent.scrollLeft;

              // It's position relative to the target's offset parent (absolute positioning when
              // the element is moved to be a child of the target's offset parent).
              next.offset = {
                top: next.page.top - offsetPosition.top + scrollTop - offsetBorder.top,
                left: next.page.left - offsetPosition.left + scrollLeft - offsetBorder.left
              };
            }
          }
        })();
      }

      // We could also travel up the DOM and try each containing context, rather than only
      // looking at the body, but we're gonna get diminishing returns.

      this.move(next);

      this.history.unshift(next);

      if (this.history.length > 3) {
        this.history.pop();
      }

      if (flushChanges) {
        flush();
      }

      return true;
    }

    // THE ISSUE
  }, {
    key: 'move',
    value: function move(pos) {
      var _this6 = this;

      if (!(typeof this.element.parentNode !== 'undefined')) {
        return;
      }

      var same = {};

      for (var type in pos) {
        same[type] = {};

        for (var key in pos[type]) {
          var found = false;

          for (var i = 0; i < this.history.length; ++i) {
            var point = this.history[i];
            if (typeof point[type] !== 'undefined' && !within(point[type][key], pos[type][key])) {
              found = true;
              break;
            }
          }

          if (!found) {
            same[type][key] = true;
          }
        }
      }

      var css = { top: '', left: '', right: '', bottom: '' };

      var transcribe = function transcribe(_same, _pos) {
        var hasOptimizations = typeof _this6.options.optimizations !== 'undefined';
        var gpu = hasOptimizations ? _this6.options.optimizations.gpu : null;
        if (gpu !== false) {
          var yPos = undefined,
              xPos = undefined;
          if (_same.top) {
            css.top = 0;
            yPos = _pos.top;
          } else {
            css.bottom = 0;
            yPos = -_pos.bottom;
          }

          if (_same.left) {
            css.left = 0;
            xPos = _pos.left;
          } else {
            css.right = 0;
            xPos = -_pos.right;
          }

          css[transformKey] = 'translateX(' + Math.round(xPos) + 'px) translateY(' + Math.round(yPos) + 'px)';

          if (transformKey !== 'msTransform') {
            // The Z transform will keep this in the GPU (faster, and prevents artifacts),
            // but IE9 doesn't support 3d transforms and will choke.
            css[transformKey] += " translateZ(0)";
          }
        } else {
          if (_same.top) {
            css.top = _pos.top + 'px';
          } else {
            css.bottom = _pos.bottom + 'px';
          }

          if (_same.left) {
            css.left = _pos.left + 'px';
          } else {
            css.right = _pos.right + 'px';
          }
        }
      };

      var moved = false;
      if ((same.page.top || same.page.bottom) && (same.page.left || same.page.right)) {
        css.position = 'absolute';
        transcribe(same.page, pos.page);
      } else if ((same.viewport.top || same.viewport.bottom) && (same.viewport.left || same.viewport.right)) {
        css.position = 'fixed';
        transcribe(same.viewport, pos.viewport);
      } else if (typeof same.offset !== 'undefined' && same.offset.top && same.offset.left) {
        (function () {
          css.position = 'absolute';
          var offsetParent = _this6.cache('target-offsetparent', function () {
            return getOffsetParent(_this6.target);
          });

          if (getOffsetParent(_this6.element) !== offsetParent) {
            defer(function () {
              _this6.element.parentNode.removeChild(_this6.element);
              offsetParent.appendChild(_this6.element);
            });
          }

          transcribe(same.offset, pos.offset);
          moved = true;
        })();
      } else {
        css.position = 'absolute';
        transcribe({ top: true, left: true }, pos.page);
      }

      if (!moved) {
        var offsetParentIsBody = true;
        var currentNode = this.element.parentNode;
        while (currentNode && currentNode.tagName !== 'BODY') {
          if (getComputedStyle(currentNode).position !== 'static') {
            offsetParentIsBody = false;
            break;
          }

          currentNode = currentNode.parentNode;
        }

        if (!offsetParentIsBody) {
          this.element.parentNode.removeChild(this.element);
          document.body.appendChild(this.element);
        }
      }

      // Any css change will trigger a repaint, so let's avoid one if nothing changed
      var writeCSS = {};
      var write = false;
      for (var key in css) {
        var val = css[key];
        var elVal = this.element.style[key];

        if (elVal !== '' && val !== '' && ['top', 'left', 'bottom', 'right'].indexOf(key) >= 0) {
          elVal = parseFloat(elVal);
          val = parseFloat(val);
        }

        if (elVal !== val) {
          write = true;
          writeCSS[key] = val;
        }
      }

      if (write) {
        defer(function () {
          extend(_this6.element.style, writeCSS);
        });
      }
    }
  }]);

  return TetherClass;
})();

TetherClass.modules = [];

TetherBase.position = position;

var Tether = extend(TetherClass, TetherBase);
/* globals TetherBase */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

var _TetherBase$Utils = TetherBase.Utils;
var getBounds = _TetherBase$Utils.getBounds;
var extend = _TetherBase$Utils.extend;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;

var BOUNDS_FORMAT = ['left', 'top', 'right', 'bottom'];

function getBoundingRect(tether, to) {
  if (to === 'scrollParent') {
    to = tether.scrollParent;
  } else if (to === 'window') {
    to = [pageXOffset, pageYOffset, innerWidth + pageXOffset, innerHeight + pageYOffset];
  }

  if (to === document) {
    to = to.documentElement;
  }

  if (typeof to.nodeType !== 'undefined') {
    (function () {
      var size = getBounds(to);
      var pos = size;
      var style = getComputedStyle(to);

      to = [pos.left, pos.top, size.width + pos.left, size.height + pos.top];

      BOUNDS_FORMAT.forEach(function (side, i) {
        side = side[0].toUpperCase() + side.substr(1);
        if (side === 'Top' || side === 'Left') {
          to[i] += parseFloat(style['border' + side + 'Width']);
        } else {
          to[i] -= parseFloat(style['border' + side + 'Width']);
        }
      });
    })();
  }

  return to;
}

TetherBase.modules.push({
  position: function position(_ref) {
    var _this = this;

    var top = _ref.top;
    var left = _ref.left;
    var targetAttachment = _ref.targetAttachment;

    if (!this.options.constraints) {
      return true;
    }

    var _cache = this.cache('element-bounds', function () {
      return getBounds(_this.element);
    });

    var height = _cache.height;
    var width = _cache.width;

    if (width === 0 && height === 0 && typeof this.lastSize !== 'undefined') {
      var _lastSize = this.lastSize;

      // Handle the item getting hidden as a result of our positioning without glitching
      // the classes in and out
      width = _lastSize.width;
      height = _lastSize.height;
    }

    var targetSize = this.cache('target-bounds', function () {
      return _this.getTargetBounds();
    });

    var targetHeight = targetSize.height;
    var targetWidth = targetSize.width;

    var allClasses = [this.getClass('pinned'), this.getClass('out-of-bounds')];

    this.options.constraints.forEach(function (constraint) {
      var outOfBoundsClass = constraint.outOfBoundsClass;
      var pinnedClass = constraint.pinnedClass;

      if (outOfBoundsClass) {
        allClasses.push(outOfBoundsClass);
      }
      if (pinnedClass) {
        allClasses.push(pinnedClass);
      }
    });

    allClasses.forEach(function (cls) {
      ['left', 'top', 'right', 'bottom'].forEach(function (side) {
        allClasses.push(cls + '-' + side);
      });
    });

    var addClasses = [];

    var tAttachment = extend({}, targetAttachment);
    var eAttachment = extend({}, this.attachment);

    this.options.constraints.forEach(function (constraint) {
      var to = constraint.to;
      var attachment = constraint.attachment;
      var pin = constraint.pin;

      if (typeof attachment === 'undefined') {
        attachment = '';
      }

      var changeAttachX = undefined,
          changeAttachY = undefined;
      if (attachment.indexOf(' ') >= 0) {
        var _attachment$split = attachment.split(' ');

        var _attachment$split2 = _slicedToArray(_attachment$split, 2);

        changeAttachY = _attachment$split2[0];
        changeAttachX = _attachment$split2[1];
      } else {
        changeAttachX = changeAttachY = attachment;
      }

      var bounds = getBoundingRect(_this, to);

      if (changeAttachY === 'target' || changeAttachY === 'both') {
        if (top < bounds[1] && tAttachment.top === 'top') {
          top += targetHeight;
          tAttachment.top = 'bottom';
        }

        if (top + height > bounds[3] && tAttachment.top === 'bottom') {
          top -= targetHeight;
          tAttachment.top = 'top';
        }
      }

      if (changeAttachY === 'together') {
        if (top < bounds[1] && tAttachment.top === 'top') {
          if (eAttachment.top === 'bottom') {
            top += targetHeight;
            tAttachment.top = 'bottom';

            top += height;
            eAttachment.top = 'top';
          } else if (eAttachment.top === 'top') {
            top += targetHeight;
            tAttachment.top = 'bottom';

            top -= height;
            eAttachment.top = 'bottom';
          }
        }

        if (top + height > bounds[3] && tAttachment.top === 'bottom') {
          if (eAttachment.top === 'top') {
            top -= targetHeight;
            tAttachment.top = 'top';

            top -= height;
            eAttachment.top = 'bottom';
          } else if (eAttachment.top === 'bottom') {
            top -= targetHeight;
            tAttachment.top = 'top';

            top += height;
            eAttachment.top = 'top';
          }
        }

        if (tAttachment.top === 'middle') {
          if (top + height > bounds[3] && eAttachment.top === 'top') {
            top -= height;
            eAttachment.top = 'bottom';
          } else if (top < bounds[1] && eAttachment.top === 'bottom') {
            top += height;
            eAttachment.top = 'top';
          }
        }
      }

      if (changeAttachX === 'target' || changeAttachX === 'both') {
        if (left < bounds[0] && tAttachment.left === 'left') {
          left += targetWidth;
          tAttachment.left = 'right';
        }

        if (left + width > bounds[2] && tAttachment.left === 'right') {
          left -= targetWidth;
          tAttachment.left = 'left';
        }
      }

      if (changeAttachX === 'together') {
        if (left < bounds[0] && tAttachment.left === 'left') {
          if (eAttachment.left === 'right') {
            left += targetWidth;
            tAttachment.left = 'right';

            left += width;
            eAttachment.left = 'left';
          } else if (eAttachment.left === 'left') {
            left += targetWidth;
            tAttachment.left = 'right';

            left -= width;
            eAttachment.left = 'right';
          }
        } else if (left + width > bounds[2] && tAttachment.left === 'right') {
          if (eAttachment.left === 'left') {
            left -= targetWidth;
            tAttachment.left = 'left';

            left -= width;
            eAttachment.left = 'right';
          } else if (eAttachment.left === 'right') {
            left -= targetWidth;
            tAttachment.left = 'left';

            left += width;
            eAttachment.left = 'left';
          }
        } else if (tAttachment.left === 'center') {
          if (left + width > bounds[2] && eAttachment.left === 'left') {
            left -= width;
            eAttachment.left = 'right';
          } else if (left < bounds[0] && eAttachment.left === 'right') {
            left += width;
            eAttachment.left = 'left';
          }
        }
      }

      if (changeAttachY === 'element' || changeAttachY === 'both') {
        if (top < bounds[1] && eAttachment.top === 'bottom') {
          top += height;
          eAttachment.top = 'top';
        }

        if (top + height > bounds[3] && eAttachment.top === 'top') {
          top -= height;
          eAttachment.top = 'bottom';
        }
      }

      if (changeAttachX === 'element' || changeAttachX === 'both') {
        if (left < bounds[0]) {
          if (eAttachment.left === 'right') {
            left += width;
            eAttachment.left = 'left';
          } else if (eAttachment.left === 'center') {
            left += width / 2;
            eAttachment.left = 'left';
          }
        }

        if (left + width > bounds[2]) {
          if (eAttachment.left === 'left') {
            left -= width;
            eAttachment.left = 'right';
          } else if (eAttachment.left === 'center') {
            left -= width / 2;
            eAttachment.left = 'right';
          }
        }
      }

      if (typeof pin === 'string') {
        pin = pin.split(',').map(function (p) {
          return p.trim();
        });
      } else if (pin === true) {
        pin = ['top', 'left', 'right', 'bottom'];
      }

      pin = pin || [];

      var pinned = [];
      var oob = [];

      if (top < bounds[1]) {
        if (pin.indexOf('top') >= 0) {
          top = bounds[1];
          pinned.push('top');
        } else {
          oob.push('top');
        }
      }

      if (top + height > bounds[3]) {
        if (pin.indexOf('bottom') >= 0) {
          top = bounds[3] - height;
          pinned.push('bottom');
        } else {
          oob.push('bottom');
        }
      }

      if (left < bounds[0]) {
        if (pin.indexOf('left') >= 0) {
          left = bounds[0];
          pinned.push('left');
        } else {
          oob.push('left');
        }
      }

      if (left + width > bounds[2]) {
        if (pin.indexOf('right') >= 0) {
          left = bounds[2] - width;
          pinned.push('right');
        } else {
          oob.push('right');
        }
      }

      if (pinned.length) {
        (function () {
          var pinnedClass = undefined;
          if (typeof _this.options.pinnedClass !== 'undefined') {
            pinnedClass = _this.options.pinnedClass;
          } else {
            pinnedClass = _this.getClass('pinned');
          }

          addClasses.push(pinnedClass);
          pinned.forEach(function (side) {
            addClasses.push(pinnedClass + '-' + side);
          });
        })();
      }

      if (oob.length) {
        (function () {
          var oobClass = undefined;
          if (typeof _this.options.outOfBoundsClass !== 'undefined') {
            oobClass = _this.options.outOfBoundsClass;
          } else {
            oobClass = _this.getClass('out-of-bounds');
          }

          addClasses.push(oobClass);
          oob.forEach(function (side) {
            addClasses.push(oobClass + '-' + side);
          });
        })();
      }

      if (pinned.indexOf('left') >= 0 || pinned.indexOf('right') >= 0) {
        eAttachment.left = tAttachment.left = false;
      }
      if (pinned.indexOf('top') >= 0 || pinned.indexOf('bottom') >= 0) {
        eAttachment.top = tAttachment.top = false;
      }

      if (tAttachment.top !== targetAttachment.top || tAttachment.left !== targetAttachment.left || eAttachment.top !== _this.attachment.top || eAttachment.left !== _this.attachment.left) {
        _this.updateAttachClasses(eAttachment, tAttachment);
      }
    });

    defer(function () {
      if (!(_this.options.addTargetClasses === false)) {
        updateClasses(_this.target, addClasses, allClasses);
      }
      updateClasses(_this.element, addClasses, allClasses);
    });

    return { top: top, left: left };
  }
});
/* globals TetherBase */

'use strict';

var _TetherBase$Utils = TetherBase.Utils;
var getBounds = _TetherBase$Utils.getBounds;
var updateClasses = _TetherBase$Utils.updateClasses;
var defer = _TetherBase$Utils.defer;

TetherBase.modules.push({
  position: function position(_ref) {
    var _this = this;

    var top = _ref.top;
    var left = _ref.left;

    var _cache = this.cache('element-bounds', function () {
      return getBounds(_this.element);
    });

    var height = _cache.height;
    var width = _cache.width;

    var targetPos = this.getTargetBounds();

    var bottom = top + height;
    var right = left + width;

    var abutted = [];
    if (top <= targetPos.bottom && bottom >= targetPos.top) {
      ['left', 'right'].forEach(function (side) {
        var targetPosSide = targetPos[side];
        if (targetPosSide === left || targetPosSide === right) {
          abutted.push(side);
        }
      });
    }

    if (left <= targetPos.right && right >= targetPos.left) {
      ['top', 'bottom'].forEach(function (side) {
        var targetPosSide = targetPos[side];
        if (targetPosSide === top || targetPosSide === bottom) {
          abutted.push(side);
        }
      });
    }

    var allClasses = [];
    var addClasses = [];

    var sides = ['left', 'top', 'right', 'bottom'];
    allClasses.push(this.getClass('abutted'));
    sides.forEach(function (side) {
      allClasses.push(_this.getClass('abutted') + '-' + side);
    });

    if (abutted.length) {
      addClasses.push(this.getClass('abutted'));
    }

    abutted.forEach(function (side) {
      addClasses.push(_this.getClass('abutted') + '-' + side);
    });

    defer(function () {
      if (!(_this.options.addTargetClasses === false)) {
        updateClasses(_this.target, addClasses, allClasses);
      }
      updateClasses(_this.element, addClasses, allClasses);
    });

    return true;
  }
});
/* globals TetherBase */

'use strict';

var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

TetherBase.modules.push({
  position: function position(_ref) {
    var top = _ref.top;
    var left = _ref.left;

    if (!this.options.shift) {
      return;
    }

    var shift = this.options.shift;
    if (typeof this.options.shift === 'function') {
      shift = this.options.shift.call(this, { top: top, left: left });
    }

    var shiftTop = undefined,
        shiftLeft = undefined;
    if (typeof shift === 'string') {
      shift = shift.split(' ');
      shift[1] = shift[1] || shift[0];

      var _shift = shift;

      var _shift2 = _slicedToArray(_shift, 2);

      shiftTop = _shift2[0];
      shiftLeft = _shift2[1];

      shiftTop = parseFloat(shiftTop, 10);
      shiftLeft = parseFloat(shiftLeft, 10);
    } else {
      shiftTop = shift.top;
      shiftLeft = shift.left;
    }

    top += shiftTop;
    left += shiftLeft;

    return { top: top, left: left };
  }
});
return Tether;

}));

},{}],199:[function(require,module,exports){
/*
 * Toastr
 * Copyright 2012-2015
 * Authors: John Papa, Hans Fjällemark, and Tim Ferrell.
 * All Rights Reserved.
 * Use, reproduction, distribution, and modification of this code is subject to the terms and
 * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
 *
 * ARIA Support: Greta Krafsig
 *
 * Project: https://github.com/CodeSeven/toastr
 */
/* global define */
; (function (define) {
    define(['jquery'], function ($) {
        return (function () {
            var $container;
            var listener;
            var toastId = 0;
            var toastType = {
                error: 'error',
                info: 'info',
                success: 'success',
                warning: 'warning'
            };

            var toastr = {
                clear: clear,
                remove: remove,
                error: error,
                getContainer: getContainer,
                info: info,
                options: {},
                subscribe: subscribe,
                success: success,
                version: '2.1.2',
                warning: warning
            };

            var previousToast;

            return toastr;

            ////////////////

            function error(message, title, optionsOverride) {
                return notify({
                    type: toastType.error,
                    iconClass: getOptions().iconClasses.error,
                    message: message,
                    optionsOverride: optionsOverride,
                    title: title
                });
            }

            function getContainer(options, create) {
                if (!options) { options = getOptions(); }
                $container = $('#' + options.containerId);
                if ($container.length) {
                    return $container;
                }
                if (create) {
                    $container = createContainer(options);
                }
                return $container;
            }

            function info(message, title, optionsOverride) {
                return notify({
                    type: toastType.info,
                    iconClass: getOptions().iconClasses.info,
                    message: message,
                    optionsOverride: optionsOverride,
                    title: title
                });
            }

            function subscribe(callback) {
                listener = callback;
            }

            function success(message, title, optionsOverride) {
                return notify({
                    type: toastType.success,
                    iconClass: getOptions().iconClasses.success,
                    message: message,
                    optionsOverride: optionsOverride,
                    title: title
                });
            }

            function warning(message, title, optionsOverride) {
                return notify({
                    type: toastType.warning,
                    iconClass: getOptions().iconClasses.warning,
                    message: message,
                    optionsOverride: optionsOverride,
                    title: title
                });
            }

            function clear($toastElement, clearOptions) {
                var options = getOptions();
                if (!$container) { getContainer(options); }
                if (!clearToast($toastElement, options, clearOptions)) {
                    clearContainer(options);
                }
            }

            function remove($toastElement) {
                var options = getOptions();
                if (!$container) { getContainer(options); }
                if ($toastElement && $(':focus', $toastElement).length === 0) {
                    removeToast($toastElement);
                    return;
                }
                if ($container.children().length) {
                    $container.remove();
                }
            }

            // internal functions

            function clearContainer (options) {
                var toastsToClear = $container.children();
                for (var i = toastsToClear.length - 1; i >= 0; i--) {
                    clearToast($(toastsToClear[i]), options);
                }
            }

            function clearToast ($toastElement, options, clearOptions) {
                var force = clearOptions && clearOptions.force ? clearOptions.force : false;
                if ($toastElement && (force || $(':focus', $toastElement).length === 0)) {
                    $toastElement[options.hideMethod]({
                        duration: options.hideDuration,
                        easing: options.hideEasing,
                        complete: function () { removeToast($toastElement); }
                    });
                    return true;
                }
                return false;
            }

            function createContainer(options) {
                $container = $('<div/>')
                    .attr('id', options.containerId)
                    .addClass(options.positionClass)
                    .attr('aria-live', 'polite')
                    .attr('role', 'alert');

                $container.appendTo($(options.target));
                return $container;
            }

            function getDefaults() {
                return {
                    tapToDismiss: true,
                    toastClass: 'toast',
                    containerId: 'toast-container',
                    debug: false,

                    showMethod: 'fadeIn', //fadeIn, slideDown, and show are built into jQuery
                    showDuration: 300,
                    showEasing: 'swing', //swing and linear are built into jQuery
                    onShown: undefined,
                    hideMethod: 'fadeOut',
                    hideDuration: 1000,
                    hideEasing: 'swing',
                    onHidden: undefined,
                    closeMethod: false,
                    closeDuration: false,
                    closeEasing: false,

                    extendedTimeOut: 1000,
                    iconClasses: {
                        error: 'toast-error',
                        info: 'toast-info',
                        success: 'toast-success',
                        warning: 'toast-warning'
                    },
                    iconClass: 'toast-info',
                    positionClass: 'toast-top-right',
                    timeOut: 5000, // Set timeOut and extendedTimeOut to 0 to make it sticky
                    titleClass: 'toast-title',
                    messageClass: 'toast-message',
                    escapeHtml: false,
                    target: 'body',
                    closeHtml: '<button type="button">&times;</button>',
                    newestOnTop: true,
                    preventDuplicates: false,
                    progressBar: false
                };
            }

            function publish(args) {
                if (!listener) { return; }
                listener(args);
            }

            function notify(map) {
                var options = getOptions();
                var iconClass = map.iconClass || options.iconClass;

                if (typeof (map.optionsOverride) !== 'undefined') {
                    options = $.extend(options, map.optionsOverride);
                    iconClass = map.optionsOverride.iconClass || iconClass;
                }

                if (shouldExit(options, map)) { return; }

                toastId++;

                $container = getContainer(options, true);

                var intervalId = null;
                var $toastElement = $('<div/>');
                var $titleElement = $('<div/>');
                var $messageElement = $('<div/>');
                var $progressElement = $('<div/>');
                var $closeElement = $(options.closeHtml);
                var progressBar = {
                    intervalId: null,
                    hideEta: null,
                    maxHideTime: null
                };
                var response = {
                    toastId: toastId,
                    state: 'visible',
                    startTime: new Date(),
                    options: options,
                    map: map
                };

                personalizeToast();

                displayToast();

                handleEvents();

                publish(response);

                if (options.debug && console) {
                    console.log(response);
                }

                return $toastElement;

                function escapeHtml(source) {
                    if (source == null)
                        source = "";

                    return new String(source)
                        .replace(/&/g, '&amp;')
                        .replace(/"/g, '&quot;')
                        .replace(/'/g, '&#39;')
                        .replace(/</g, '&lt;')
                        .replace(/>/g, '&gt;');
                }

                function personalizeToast() {
                    setIcon();
                    setTitle();
                    setMessage();
                    setCloseButton();
                    setProgressBar();
                    setSequence();
                }

                function handleEvents() {
                    $toastElement.hover(stickAround, delayedHideToast);
                    if (!options.onclick && options.tapToDismiss) {
                        $toastElement.click(hideToast);
                    }

                    if (options.closeButton && $closeElement) {
                        $closeElement.click(function (event) {
                            if (event.stopPropagation) {
                                event.stopPropagation();
                            } else if (event.cancelBubble !== undefined && event.cancelBubble !== true) {
                                event.cancelBubble = true;
                            }
                            hideToast(true);
                        });
                    }

                    if (options.onclick) {
                        $toastElement.click(function (event) {
                            options.onclick(event);
                            hideToast();
                        });
                    }
                }

                function displayToast() {
                    $toastElement.hide();

                    $toastElement[options.showMethod](
                        {duration: options.showDuration, easing: options.showEasing, complete: options.onShown}
                    );

                    if (options.timeOut > 0) {
                        intervalId = setTimeout(hideToast, options.timeOut);
                        progressBar.maxHideTime = parseFloat(options.timeOut);
                        progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
                        if (options.progressBar) {
                            progressBar.intervalId = setInterval(updateProgress, 10);
                        }
                    }
                }

                function setIcon() {
                    if (map.iconClass) {
                        $toastElement.addClass(options.toastClass).addClass(iconClass);
                    }
                }

                function setSequence() {
                    if (options.newestOnTop) {
                        $container.prepend($toastElement);
                    } else {
                        $container.append($toastElement);
                    }
                }

                function setTitle() {
                    if (map.title) {
                        $titleElement.append(!options.escapeHtml ? map.title : escapeHtml(map.title)).addClass(options.titleClass);
                        $toastElement.append($titleElement);
                    }
                }

                function setMessage() {
                    if (map.message) {
                        $messageElement.append(!options.escapeHtml ? map.message : escapeHtml(map.message)).addClass(options.messageClass);
                        $toastElement.append($messageElement);
                    }
                }

                function setCloseButton() {
                    if (options.closeButton) {
                        $closeElement.addClass('toast-close-button').attr('role', 'button');
                        $toastElement.prepend($closeElement);
                    }
                }

                function setProgressBar() {
                    if (options.progressBar) {
                        $progressElement.addClass('toast-progress');
                        $toastElement.prepend($progressElement);
                    }
                }

                function shouldExit(options, map) {
                    if (options.preventDuplicates) {
                        if (map.message === previousToast) {
                            return true;
                        } else {
                            previousToast = map.message;
                        }
                    }
                    return false;
                }

                function hideToast(override) {
                    var method = override && options.closeMethod !== false ? options.closeMethod : options.hideMethod;
                    var duration = override && options.closeDuration !== false ?
                        options.closeDuration : options.hideDuration;
                    var easing = override && options.closeEasing !== false ? options.closeEasing : options.hideEasing;
                    if ($(':focus', $toastElement).length && !override) {
                        return;
                    }
                    clearTimeout(progressBar.intervalId);
                    return $toastElement[method]({
                        duration: duration,
                        easing: easing,
                        complete: function () {
                            removeToast($toastElement);
                            if (options.onHidden && response.state !== 'hidden') {
                                options.onHidden();
                            }
                            response.state = 'hidden';
                            response.endTime = new Date();
                            publish(response);
                        }
                    });
                }

                function delayedHideToast() {
                    if (options.timeOut > 0 || options.extendedTimeOut > 0) {
                        intervalId = setTimeout(hideToast, options.extendedTimeOut);
                        progressBar.maxHideTime = parseFloat(options.extendedTimeOut);
                        progressBar.hideEta = new Date().getTime() + progressBar.maxHideTime;
                    }
                }

                function stickAround() {
                    clearTimeout(intervalId);
                    progressBar.hideEta = 0;
                    $toastElement.stop(true, true)[options.showMethod](
                        {duration: options.showDuration, easing: options.showEasing}
                    );
                }

                function updateProgress() {
                    var percentage = ((progressBar.hideEta - (new Date().getTime())) / progressBar.maxHideTime) * 100;
                    $progressElement.width(percentage + '%');
                }
            }

            function getOptions() {
                return $.extend({}, getDefaults(), toastr.options);
            }

            function removeToast($toastElement) {
                if (!$container) { $container = getContainer(); }
                if ($toastElement.is(':visible')) {
                    return;
                }
                $toastElement.remove();
                $toastElement = null;
                if ($container.children().length === 0) {
                    $container.remove();
                    previousToast = undefined;
                }
            }

        })();
    });
}(typeof define === 'function' && define.amd ? define : function (deps, factory) {
    if (typeof module !== 'undefined' && module.exports) { //Node
        module.exports = factory(require('jquery'));
    } else {
        window.toastr = factory(window.jQuery);
    }
}));

},{"jquery":214}],200:[function(require,module,exports){
/**
* @version: 2.1.30
* @author: Dan Grossman http://www.dangrossman.info/
* @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved.
* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php
* @website: http://www.daterangepicker.com/
*/
// Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Make globaly available as well
        define(['moment', 'jquery'], function (moment, jquery) {
            if (!jquery.fn) jquery.fn = {}; // webpack server rendering
            return factory(moment, jquery);
        });
    } else if (typeof module === 'object' && module.exports) {
        // Node / Browserify
        //isomorphic issue
        var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined;
        if (!jQuery) {
            jQuery = require('jquery');
            if (!jQuery.fn) jQuery.fn = {};
        }
        var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment');
        module.exports = factory(moment, jQuery);
    } else {
        // Browser globals
        root.daterangepicker = factory(root.moment, root.jQuery);
    }
}(this, function(moment, $) {
    var DateRangePicker = function(element, options, cb) {

        //default settings for options
        this.parentEl = 'body';
        this.element = $(element);
        this.startDate = moment().startOf('day');
        this.endDate = moment().endOf('day');
        this.minDate = false;
        this.maxDate = false;
        this.dateLimit = false;
        this.autoApply = false;
        this.singleDatePicker = false;
        this.showDropdowns = false;
        this.showWeekNumbers = false;
        this.showISOWeekNumbers = false;
        this.showCustomRangeLabel = true;
        this.timePicker = false;
        this.timePicker24Hour = false;
        this.timePickerIncrement = 1;
        this.timePickerSeconds = false;
        this.linkedCalendars = true;
        this.autoUpdateInput = true;
        this.alwaysShowCalendars = false;
        this.ranges = {};

        this.opens = 'right';
        if (this.element.hasClass('pull-right'))
            this.opens = 'left';

        this.drops = 'down';
        if (this.element.hasClass('dropup'))
            this.drops = 'up';

        this.buttonClasses = 'btn btn-sm';
        this.applyClass = 'btn-success';
        this.cancelClass = 'btn-default';

        this.locale = {
            direction: 'ltr',
            format: moment.localeData().longDateFormat('L'),
            separator: ' - ',
            applyLabel: 'Apply',
            cancelLabel: 'Cancel',
            weekLabel: 'W',
            customRangeLabel: 'Custom Range',
            daysOfWeek: moment.weekdaysMin(),
            monthNames: moment.monthsShort(),
            firstDay: moment.localeData().firstDayOfWeek()
        };

        this.callback = function() { };

        //some state information
        this.isShowing = false;
        this.leftCalendar = {};
        this.rightCalendar = {};

        //custom options from user
        if (typeof options !== 'object' || options === null)
            options = {};

        //allow setting options with data attributes
        //data-api options will be overwritten with custom javascript options
        options = $.extend(this.element.data(), options);

        //html template for the picker UI
        if (typeof options.template !== 'string' && !(options.template instanceof $))
            options.template = '<div class="daterangepicker dropdown-menu">' +
                '<div class="calendar left">' +
                    '<div class="daterangepicker_input">' +
                      '<input class="input-mini form-control" type="text" name="daterangepicker_start" value="" />' +
                      '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
                      '<div class="calendar-time">' +
                        '<div></div>' +
                        '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
                      '</div>' +
                    '</div>' +
                    '<div class="calendar-table"></div>' +
                '</div>' +
                '<div class="calendar right">' +
                    '<div class="daterangepicker_input">' +
                      '<input class="input-mini form-control" type="text" name="daterangepicker_end" value="" />' +
                      '<i class="fa fa-calendar glyphicon glyphicon-calendar"></i>' +
                      '<div class="calendar-time">' +
                        '<div></div>' +
                        '<i class="fa fa-clock-o glyphicon glyphicon-time"></i>' +
                      '</div>' +
                    '</div>' +
                    '<div class="calendar-table"></div>' +
                '</div>' +
                '<div class="ranges">' +
                    '<div class="range_inputs">' +
                        '<button class="applyBtn" disabled="disabled" type="button"></button> ' +
                        '<button class="cancelBtn" type="button"></button>' +
                    '</div>' +
                '</div>' +
            '</div>';

        this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl);
        this.container = $(options.template).appendTo(this.parentEl);

        //
        // handle all the possible options overriding defaults
        //

        if (typeof options.locale === 'object') {

            if (typeof options.locale.direction === 'string')
                this.locale.direction = options.locale.direction;

            if (typeof options.locale.format === 'string')
                this.locale.format = options.locale.format;

            if (typeof options.locale.separator === 'string')
                this.locale.separator = options.locale.separator;

            if (typeof options.locale.daysOfWeek === 'object')
                this.locale.daysOfWeek = options.locale.daysOfWeek.slice();

            if (typeof options.locale.monthNames === 'object')
              this.locale.monthNames = options.locale.monthNames.slice();

            if (typeof options.locale.firstDay === 'number')
              this.locale.firstDay = options.locale.firstDay;

            if (typeof options.locale.applyLabel === 'string')
              this.locale.applyLabel = options.locale.applyLabel;

            if (typeof options.locale.cancelLabel === 'string')
              this.locale.cancelLabel = options.locale.cancelLabel;

            if (typeof options.locale.weekLabel === 'string')
              this.locale.weekLabel = options.locale.weekLabel;

            if (typeof options.locale.customRangeLabel === 'string'){
                //Support unicode chars in the custom range name.
                var elem = document.createElement('textarea');
                elem.innerHTML = options.locale.customRangeLabel;
                var rangeHtml = elem.value;
                this.locale.customRangeLabel = rangeHtml;
            }
        }
        this.container.addClass(this.locale.direction);

        if (typeof options.startDate === 'string')
            this.startDate = moment(options.startDate, this.locale.format);

        if (typeof options.endDate === 'string')
            this.endDate = moment(options.endDate, this.locale.format);

        if (typeof options.minDate === 'string')
            this.minDate = moment(options.minDate, this.locale.format);

        if (typeof options.maxDate === 'string')
            this.maxDate = moment(options.maxDate, this.locale.format);

        if (typeof options.startDate === 'object')
            this.startDate = moment(options.startDate);

        if (typeof options.endDate === 'object')
            this.endDate = moment(options.endDate);

        if (typeof options.minDate === 'object')
            this.minDate = moment(options.minDate);

        if (typeof options.maxDate === 'object')
            this.maxDate = moment(options.maxDate);

        // sanity check for bad options
        if (this.minDate && this.startDate.isBefore(this.minDate))
            this.startDate = this.minDate.clone();

        // sanity check for bad options
        if (this.maxDate && this.endDate.isAfter(this.maxDate))
            this.endDate = this.maxDate.clone();

        if (typeof options.applyClass === 'string')
            this.applyClass = options.applyClass;

        if (typeof options.cancelClass === 'string')
            this.cancelClass = options.cancelClass;

        if (typeof options.dateLimit === 'object')
            this.dateLimit = options.dateLimit;

        if (typeof options.opens === 'string')
            this.opens = options.opens;

        if (typeof options.drops === 'string')
            this.drops = options.drops;

        if (typeof options.showWeekNumbers === 'boolean')
            this.showWeekNumbers = options.showWeekNumbers;

        if (typeof options.showISOWeekNumbers === 'boolean')
            this.showISOWeekNumbers = options.showISOWeekNumbers;

        if (typeof options.buttonClasses === 'string')
            this.buttonClasses = options.buttonClasses;

        if (typeof options.buttonClasses === 'object')
            this.buttonClasses = options.buttonClasses.join(' ');

        if (typeof options.showDropdowns === 'boolean')
            this.showDropdowns = options.showDropdowns;

        if (typeof options.showCustomRangeLabel === 'boolean')
            this.showCustomRangeLabel = options.showCustomRangeLabel;

        if (typeof options.singleDatePicker === 'boolean') {
            this.singleDatePicker = options.singleDatePicker;
            if (this.singleDatePicker)
                this.endDate = this.startDate.clone();
        }

        if (typeof options.timePicker === 'boolean')
            this.timePicker = options.timePicker;

        if (typeof options.timePickerSeconds === 'boolean')
            this.timePickerSeconds = options.timePickerSeconds;

        if (typeof options.timePickerIncrement === 'number')
            this.timePickerIncrement = options.timePickerIncrement;

        if (typeof options.timePicker24Hour === 'boolean')
            this.timePicker24Hour = options.timePicker24Hour;

        if (typeof options.autoApply === 'boolean')
            this.autoApply = options.autoApply;

        if (typeof options.autoUpdateInput === 'boolean')
            this.autoUpdateInput = options.autoUpdateInput;

        if (typeof options.linkedCalendars === 'boolean')
            this.linkedCalendars = options.linkedCalendars;

        if (typeof options.isInvalidDate === 'function')
            this.isInvalidDate = options.isInvalidDate;

        if (typeof options.isCustomDate === 'function')
            this.isCustomDate = options.isCustomDate;

        if (typeof options.alwaysShowCalendars === 'boolean')
            this.alwaysShowCalendars = options.alwaysShowCalendars;

        // update day names order to firstDay
        if (this.locale.firstDay != 0) {
            var iterator = this.locale.firstDay;
            while (iterator > 0) {
                this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift());
                iterator--;
            }
        }

        var start, end, range;

        //if no start/end dates set, check if an input element contains initial values
        if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') {
            if ($(this.element).is('input[type=text]')) {
                var val = $(this.element).val(),
                    split = val.split(this.locale.separator);

                start = end = null;

                if (split.length == 2) {
                    start = moment(split[0], this.locale.format);
                    end = moment(split[1], this.locale.format);
                } else if (this.singleDatePicker && val !== "") {
                    start = moment(val, this.locale.format);
                    end = moment(val, this.locale.format);
                }
                if (start !== null && end !== null) {
                    this.setStartDate(start);
                    this.setEndDate(end);
                }
            }
        }

        if (typeof options.ranges === 'object') {
            for (range in options.ranges) {

                if (typeof options.ranges[range][0] === 'string')
                    start = moment(options.ranges[range][0], this.locale.format);
                else
                    start = moment(options.ranges[range][0]);

                if (typeof options.ranges[range][1] === 'string')
                    end = moment(options.ranges[range][1], this.locale.format);
                else
                    end = moment(options.ranges[range][1]);

                // If the start or end date exceed those allowed by the minDate or dateLimit
                // options, shorten the range to the allowable period.
                if (this.minDate && start.isBefore(this.minDate))
                    start = this.minDate.clone();

                var maxDate = this.maxDate;
                if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate))
                    maxDate = start.clone().add(this.dateLimit);
                if (maxDate && end.isAfter(maxDate))
                    end = maxDate.clone();

                // If the end of the range is before the minimum or the start of the range is
                // after the maximum, don't display this range option at all.
                if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) 
                  || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day')))
                    continue;

                //Support unicode chars in the range names.
                var elem = document.createElement('textarea');
                elem.innerHTML = range;
                var rangeHtml = elem.value;

                this.ranges[rangeHtml] = [start, end];
            }

            var list = '<ul>';
            for (range in this.ranges) {
                list += '<li data-range-key="' + range + '">' + range + '</li>';
            }
            if (this.showCustomRangeLabel) {
                list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>';
            }
            list += '</ul>';
            this.container.find('.ranges').prepend(list);
        }

        if (typeof cb === 'function') {
            this.callback = cb;
        }

        if (!this.timePicker) {
            this.startDate = this.startDate.startOf('day');
            this.endDate = this.endDate.endOf('day');
            this.container.find('.calendar-time').hide();
        }

        //can't be used together for now
        if (this.timePicker && this.autoApply)
            this.autoApply = false;

        if (this.autoApply && typeof options.ranges !== 'object') {
            this.container.find('.ranges').hide();
        } else if (this.autoApply) {
            this.container.find('.applyBtn, .cancelBtn').addClass('hide');
        }

        if (this.singleDatePicker) {
            this.container.addClass('single');
            this.container.find('.calendar.left').addClass('single');
            this.container.find('.calendar.left').show();
            this.container.find('.calendar.right').hide();
            this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide();
            if (this.timePicker) {
                this.container.find('.ranges ul').hide();
            } else {
                this.container.find('.ranges').hide();
            }
        }

        if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) {
            this.container.addClass('show-calendar');
        }

        this.container.addClass('opens' + this.opens);

        //swap the position of the predefined ranges if opens right
        if (typeof options.ranges !== 'undefined' && this.opens == 'right') {
            this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() );
        }

        //apply CSS classes and labels to buttons
        this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses);
        if (this.applyClass.length)
            this.container.find('.applyBtn').addClass(this.applyClass);
        if (this.cancelClass.length)
            this.container.find('.cancelBtn').addClass(this.cancelClass);
        this.container.find('.applyBtn').html(this.locale.applyLabel);
        this.container.find('.cancelBtn').html(this.locale.cancelLabel);

        //
        // event listeners
        //

        this.container.find('.calendar')
            .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this))
            .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this))
            .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this))
            .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this))
            .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this))
            .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this))
            .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this))
            .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this))
            .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this))
            .on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this))
            .on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this))
            .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this))
            .on('keydown.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsKeydown, this));

        this.container.find('.ranges')
            .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this))
            .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this))
            .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this))
            .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this))
            .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this));

        if (this.element.is('input') || this.element.is('button')) {
            this.element.on({
                'click.daterangepicker': $.proxy(this.show, this),
                'focus.daterangepicker': $.proxy(this.show, this),
                'keyup.daterangepicker': $.proxy(this.elementChanged, this),
                'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility
            });
        } else {
            this.element.on('click.daterangepicker', $.proxy(this.toggle, this));
            this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this));
        }

        //
        // if attached to a text input, set the initial value
        //

        if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
            this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
            this.element.trigger('change');
        } else if (this.element.is('input') && this.autoUpdateInput) {
            this.element.val(this.startDate.format(this.locale.format));
            this.element.trigger('change');
        }

    };

    DateRangePicker.prototype = {

        constructor: DateRangePicker,

        setStartDate: function(startDate) {
            if (typeof startDate === 'string')
                this.startDate = moment(startDate, this.locale.format);

            if (typeof startDate === 'object')
                this.startDate = moment(startDate);

            if (!this.timePicker)
                this.startDate = this.startDate.startOf('day');

            if (this.timePicker && this.timePickerIncrement)
                this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);

            if (this.minDate && this.startDate.isBefore(this.minDate)) {
                this.startDate = this.minDate.clone();
                if (this.timePicker && this.timePickerIncrement)
                    this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
            }

            if (this.maxDate && this.startDate.isAfter(this.maxDate)) {
                this.startDate = this.maxDate.clone();
                if (this.timePicker && this.timePickerIncrement)
                    this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);
            }

            if (!this.isShowing)
                this.updateElement();

            this.updateMonthsInView();
        },

        setEndDate: function(endDate) {
            if (typeof endDate === 'string')
                this.endDate = moment(endDate, this.locale.format);

            if (typeof endDate === 'object')
                this.endDate = moment(endDate);

            if (!this.timePicker)
                this.endDate = this.endDate.add(1,'d').startOf('day').subtract(1,'second');

            if (this.timePicker && this.timePickerIncrement)
                this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement);

            if (this.endDate.isBefore(this.startDate))
                this.endDate = this.startDate.clone();

            if (this.maxDate && this.endDate.isAfter(this.maxDate))
                this.endDate = this.maxDate.clone();

            if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate))
                this.endDate = this.startDate.clone().add(this.dateLimit);

            this.previousRightTime = this.endDate.clone();

            if (!this.isShowing)
                this.updateElement();

            this.updateMonthsInView();
        },

        isInvalidDate: function() {
            return false;
        },

        isCustomDate: function() {
            return false;
        },

        updateView: function() {
            if (this.timePicker) {
                this.renderTimePicker('left');
                this.renderTimePicker('right');
                if (!this.endDate) {
                    this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled');
                } else {
                    this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled');
                }
            }
            if (this.endDate) {
                this.container.find('input[name="daterangepicker_end"]').removeClass('active');
                this.container.find('input[name="daterangepicker_start"]').addClass('active');
            } else {
                this.container.find('input[name="daterangepicker_end"]').addClass('active');
                this.container.find('input[name="daterangepicker_start"]').removeClass('active');
            }
            this.updateMonthsInView();
            this.updateCalendars();
            this.updateFormInputs();
        },

        updateMonthsInView: function() {
            if (this.endDate) {

                //if both dates are visible already, do nothing
                if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month &&
                    (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
                    &&
                    (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM'))
                    ) {
                    return;
                }

                this.leftCalendar.month = this.startDate.clone().date(2);
                if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) {
                    this.rightCalendar.month = this.endDate.clone().date(2);
                } else {
                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
                }

            } else {
                if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) {
                    this.leftCalendar.month = this.startDate.clone().date(2);
                    this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month');
                }
            }
            if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) {
              this.rightCalendar.month = this.maxDate.clone().date(2);
              this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month');
            }
        },

        updateCalendars: function() {

            if (this.timePicker) {
                var hour, minute, second;
                if (this.endDate) {
                    hour = parseInt(this.container.find('.left .hourselect').val(), 10);
                    minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
                    second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.left .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                } else {
                    hour = parseInt(this.container.find('.right .hourselect').val(), 10);
                    minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
                    second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.right .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                }
                this.leftCalendar.month.hour(hour).minute(minute).second(second);
                this.rightCalendar.month.hour(hour).minute(minute).second(second);
            }

            this.renderCalendar('left');
            this.renderCalendar('right');

            //highlight any predefined range matching the current start and end dates
            this.container.find('.ranges li').removeClass('active');
            if (this.endDate == null) return;

            this.calculateChosenLabel();
        },

        renderCalendar: function(side) {

            //
            // Build the matrix of dates that will populate the calendar
            //

            var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar;
            var month = calendar.month.month();
            var year = calendar.month.year();
            var hour = calendar.month.hour();
            var minute = calendar.month.minute();
            var second = calendar.month.second();
            var daysInMonth = moment([year, month]).daysInMonth();
            var firstDay = moment([year, month, 1]);
            var lastDay = moment([year, month, daysInMonth]);
            var lastMonth = moment(firstDay).subtract(1, 'month').month();
            var lastYear = moment(firstDay).subtract(1, 'month').year();
            var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth();
            var dayOfWeek = firstDay.day();

            //initialize a 6 rows x 7 columns array for the calendar
            var calendar = [];
            calendar.firstDay = firstDay;
            calendar.lastDay = lastDay;

            for (var i = 0; i < 6; i++) {
                calendar[i] = [];
            }

            //populate the calendar with date objects
            var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1;
            if (startDay > daysInLastMonth)
                startDay -= 7;

            if (dayOfWeek == this.locale.firstDay)
                startDay = daysInLastMonth - 6;

            var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]);

            var col, row;
            for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) {
                if (i > 0 && col % 7 === 0) {
                    col = 0;
                    row++;
                }
                calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second);
                curDate.hour(12);

                if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') {
                    calendar[row][col] = this.minDate.clone();
                }

                if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') {
                    calendar[row][col] = this.maxDate.clone();
                }

            }

            //make the calendar object available to hoverDate/clickDate
            if (side == 'left') {
                this.leftCalendar.calendar = calendar;
            } else {
                this.rightCalendar.calendar = calendar;
            }

            //
            // Display the calendar
            //

            var minDate = side == 'left' ? this.minDate : this.startDate;
            var maxDate = this.maxDate;
            var selected = side == 'left' ? this.startDate : this.endDate;
            var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'};

            var html = '<table class="table-condensed">';
            html += '<thead>';
            html += '<tr>';

            // add empty cell for week number
            if (this.showWeekNumbers || this.showISOWeekNumbers)
                html += '<th></th>';

            if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) {
                html += '<th class="prev available"><i class="fa fa-' + arrow.left + ' glyphicon glyphicon-' + arrow.left + '"></i></th>';
            } else {
                html += '<th></th>';
            }

            var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY");

            if (this.showDropdowns) {
                var currentMonth = calendar[1][1].month();
                var currentYear = calendar[1][1].year();
                var maxYear = (maxDate && maxDate.year()) || (currentYear + 5);
                var minYear = (minDate && minDate.year()) || (currentYear - 50);
                var inMinYear = currentYear == minYear;
                var inMaxYear = currentYear == maxYear;

                var monthHtml = '<select class="monthselect">';
                for (var m = 0; m < 12; m++) {
                    if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) {
                        monthHtml += "<option value='" + m + "'" +
                            (m === currentMonth ? " selected='selected'" : "") +
                            ">" + this.locale.monthNames[m] + "</option>";
                    } else {
                        monthHtml += "<option value='" + m + "'" +
                            (m === currentMonth ? " selected='selected'" : "") +
                            " disabled='disabled'>" + this.locale.monthNames[m] + "</option>";
                    }
                }
                monthHtml += "</select>";

                var yearHtml = '<select class="yearselect">';
                for (var y = minYear; y <= maxYear; y++) {
                    yearHtml += '<option value="' + y + '"' +
                        (y === currentYear ? ' selected="selected"' : '') +
                        '>' + y + '</option>';
                }
                yearHtml += '</select>';

                dateHtml = monthHtml + yearHtml;
            }

            html += '<th colspan="5" class="month">' + dateHtml + '</th>';
            if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) {
                html += '<th class="next available"><i class="fa fa-' + arrow.right + ' glyphicon glyphicon-' + arrow.right + '"></i></th>';
            } else {
                html += '<th></th>';
            }

            html += '</tr>';
            html += '<tr>';

            // add week number label
            if (this.showWeekNumbers || this.showISOWeekNumbers)
                html += '<th class="week">' + this.locale.weekLabel + '</th>';

            $.each(this.locale.daysOfWeek, function(index, dayOfWeek) {
                html += '<th>' + dayOfWeek + '</th>';
            });

            html += '</tr>';
            html += '</thead>';
            html += '<tbody>';

            //adjust maxDate to reflect the dateLimit setting in order to
            //grey out end dates beyond the dateLimit
            if (this.endDate == null && this.dateLimit) {
                var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day');
                if (!maxDate || maxLimit.isBefore(maxDate)) {
                    maxDate = maxLimit;
                }
            }

            for (var row = 0; row < 6; row++) {
                html += '<tr>';

                // add week number
                if (this.showWeekNumbers)
                    html += '<td class="week">' + calendar[row][0].week() + '</td>';
                else if (this.showISOWeekNumbers)
                    html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>';

                for (var col = 0; col < 7; col++) {

                    var classes = [];

                    //highlight today's date
                    if (calendar[row][col].isSame(new Date(), "day"))
                        classes.push('today');

                    //highlight weekends
                    if (calendar[row][col].isoWeekday() > 5)
                        classes.push('weekend');

                    //grey out the dates in other months displayed at beginning and end of this calendar
                    if (calendar[row][col].month() != calendar[1][1].month())
                        classes.push('off');

                    //don't allow selection of dates before the minimum date
                    if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day'))
                        classes.push('off', 'disabled');

                    //don't allow selection of dates after the maximum date
                    if (maxDate && calendar[row][col].isAfter(maxDate, 'day'))
                        classes.push('off', 'disabled');

                    //don't allow selection of date if a custom function decides it's invalid
                    if (this.isInvalidDate(calendar[row][col]))
                        classes.push('off', 'disabled');

                    //highlight the currently selected start date
                    if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD'))
                        classes.push('active', 'start-date');

                    //highlight the currently selected end date
                    if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD'))
                        classes.push('active', 'end-date');

                    //highlight dates in-between the selected dates
                    if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate)
                        classes.push('in-range');

                    //apply custom classes for this date
                    var isCustom = this.isCustomDate(calendar[row][col]);
                    if (isCustom !== false) {
                        if (typeof isCustom === 'string')
                            classes.push(isCustom);
                        else
                            Array.prototype.push.apply(classes, isCustom);
                    }

                    var cname = '', disabled = false;
                    for (var i = 0; i < classes.length; i++) {
                        cname += classes[i] + ' ';
                        if (classes[i] == 'disabled')
                            disabled = true;
                    }
                    if (!disabled)
                        cname += 'available';

                    html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '">' + calendar[row][col].date() + '</td>';

                }
                html += '</tr>';
            }

            html += '</tbody>';
            html += '</table>';

            this.container.find('.calendar.' + side + ' .calendar-table').html(html);

        },

        renderTimePicker: function(side) {

            // Don't bother updating the time picker if it's currently disabled
            // because an end date hasn't been clicked yet
            if (side == 'right' && !this.endDate) return;

            var html, selected, minDate, maxDate = this.maxDate;

            if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate)))
                maxDate = this.startDate.clone().add(this.dateLimit);

            if (side == 'left') {
                selected = this.startDate.clone();
                minDate = this.minDate;
            } else if (side == 'right') {
                selected = this.endDate.clone();
                minDate = this.startDate;

                //Preserve the time already selected
                var timeSelector = this.container.find('.calendar.right .calendar-time div');
                if (timeSelector.html() != '') {

                    selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour());
                    selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute());
                    selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second());

                    if (!this.timePicker24Hour) {
                        var ampm = timeSelector.find('.ampmselect option:selected').val();
                        if (ampm === 'PM' && selected.hour() < 12)
                            selected.hour(selected.hour() + 12);
                        if (ampm === 'AM' && selected.hour() === 12)
                            selected.hour(0);
                    }

                }

                if (selected.isBefore(this.startDate))
                    selected = this.startDate.clone();

                if (maxDate && selected.isAfter(maxDate))
                    selected = maxDate.clone();

            }

            //
            // hours
            //

            html = '<select class="hourselect">';

            var start = this.timePicker24Hour ? 0 : 1;
            var end = this.timePicker24Hour ? 23 : 12;

            for (var i = start; i <= end; i++) {
                var i_in_24 = i;
                if (!this.timePicker24Hour)
                    i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i);

                var time = selected.clone().hour(i_in_24);
                var disabled = false;
                if (minDate && time.minute(59).isBefore(minDate))
                    disabled = true;
                if (maxDate && time.minute(0).isAfter(maxDate))
                    disabled = true;

                if (i_in_24 == selected.hour() && !disabled) {
                    html += '<option value="' + i + '" selected="selected">' + i + '</option>';
                } else if (disabled) {
                    html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>';
                } else {
                    html += '<option value="' + i + '">' + i + '</option>';
                }
            }

            html += '</select> ';

            //
            // minutes
            //

            html += ': <select class="minuteselect">';

            for (var i = 0; i < 60; i += this.timePickerIncrement) {
                var padded = i < 10 ? '0' + i : i;
                var time = selected.clone().minute(i);

                var disabled = false;
                if (minDate && time.second(59).isBefore(minDate))
                    disabled = true;
                if (maxDate && time.second(0).isAfter(maxDate))
                    disabled = true;

                if (selected.minute() == i && !disabled) {
                    html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
                } else if (disabled) {
                    html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
                } else {
                    html += '<option value="' + i + '">' + padded + '</option>';
                }
            }

            html += '</select> ';

            //
            // seconds
            //

            if (this.timePickerSeconds) {
                html += ': <select class="secondselect">';

                for (var i = 0; i < 60; i++) {
                    var padded = i < 10 ? '0' + i : i;
                    var time = selected.clone().second(i);

                    var disabled = false;
                    if (minDate && time.isBefore(minDate))
                        disabled = true;
                    if (maxDate && time.isAfter(maxDate))
                        disabled = true;

                    if (selected.second() == i && !disabled) {
                        html += '<option value="' + i + '" selected="selected">' + padded + '</option>';
                    } else if (disabled) {
                        html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>';
                    } else {
                        html += '<option value="' + i + '">' + padded + '</option>';
                    }
                }

                html += '</select> ';
            }

            //
            // AM/PM
            //

            if (!this.timePicker24Hour) {
                html += '<select class="ampmselect">';

                var am_html = '';
                var pm_html = '';

                if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate))
                    am_html = ' disabled="disabled" class="disabled"';

                if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate))
                    pm_html = ' disabled="disabled" class="disabled"';

                if (selected.hour() >= 12) {
                    html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>';
                } else {
                    html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>';
                }

                html += '</select>';
            }

            this.container.find('.calendar.' + side + ' .calendar-time div').html(html);

        },

        updateFormInputs: function() {

            //ignore mouse movements while an above-calendar text input has focus
            if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
                return;

            this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format));
            if (this.endDate)
                this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format));

            if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) {
                this.container.find('button.applyBtn').removeAttr('disabled');
            } else {
                this.container.find('button.applyBtn').attr('disabled', 'disabled');
            }

        },

        move: function() {
            var parentOffset = { top: 0, left: 0 },
                containerTop;
            var parentRightEdge = $(window).width();
            if (!this.parentEl.is('body')) {
                parentOffset = {
                    top: this.parentEl.offset().top - this.parentEl.scrollTop(),
                    left: this.parentEl.offset().left - this.parentEl.scrollLeft()
                };
                parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left;
            }

            if (this.drops == 'up')
                containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top;
            else
                containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top;
            this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup');

            if (this.opens == 'left') {
                this.container.css({
                    top: containerTop,
                    right: parentRightEdge - this.element.offset().left - this.element.outerWidth(),
                    left: 'auto'
                });
                if (this.container.offset().left < 0) {
                    this.container.css({
                        right: 'auto',
                        left: 9
                    });
                }
            } else if (this.opens == 'center') {
                this.container.css({
                    top: containerTop,
                    left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2
                            - this.container.outerWidth() / 2,
                    right: 'auto'
                });
                if (this.container.offset().left < 0) {
                    this.container.css({
                        right: 'auto',
                        left: 9
                    });
                }
            } else {
                this.container.css({
                    top: containerTop,
                    left: this.element.offset().left - parentOffset.left,
                    right: 'auto'
                });
                if (this.container.offset().left + this.container.outerWidth() > $(window).width()) {
                    this.container.css({
                        left: 'auto',
                        right: 0
                    });
                }
            }
        },

        show: function(e) {
            if (this.isShowing) return;

            // Create a click proxy that is private to this instance of datepicker, for unbinding
            this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this);

            // Bind global datepicker mousedown for hiding and
            $(document)
              .on('mousedown.daterangepicker', this._outsideClickProxy)
              // also support mobile devices
              .on('touchend.daterangepicker', this._outsideClickProxy)
              // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them
              .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
              // and also close when focus changes to outside the picker (eg. tabbing between controls)
              .on('focusin.daterangepicker', this._outsideClickProxy);

            // Reposition the picker if the window is resized while it's open
            $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this));

            this.oldStartDate = this.startDate.clone();
            this.oldEndDate = this.endDate.clone();
            this.previousRightTime = this.endDate.clone();

            this.updateView();
            this.container.show();
            this.move();
            this.element.trigger('show.daterangepicker', this);
            this.isShowing = true;
        },

        hide: function(e) {
            if (!this.isShowing) return;

            //incomplete date selection, revert to last values
            if (!this.endDate) {
                this.startDate = this.oldStartDate.clone();
                this.endDate = this.oldEndDate.clone();
            }

            //if a new date range was selected, invoke the user callback function
            if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate))
                this.callback(this.startDate, this.endDate, this.chosenLabel);

            //if picker is attached to a text input, update it
            this.updateElement();

            $(document).off('.daterangepicker');
            $(window).off('.daterangepicker');
            this.container.hide();
            this.element.trigger('hide.daterangepicker', this);
            this.isShowing = false;
        },

        toggle: function(e) {
            if (this.isShowing) {
                this.hide();
            } else {
                this.show();
            }
        },

        outsideClick: function(e) {
            var target = $(e.target);
            // if the page is clicked anywhere except within the daterangerpicker/button
            // itself then call this.hide()
            if (
                // ie modal dialog fix
                e.type == "focusin" ||
                target.closest(this.element).length ||
                target.closest(this.container).length ||
                target.closest('.calendar-table').length
                ) return;
            this.hide();
            this.element.trigger('outsideClick.daterangepicker', this);
        },

        showCalendars: function() {
            this.container.addClass('show-calendar');
            this.move();
            this.element.trigger('showCalendar.daterangepicker', this);
        },

        hideCalendars: function() {
            this.container.removeClass('show-calendar');
            this.element.trigger('hideCalendar.daterangepicker', this);
        },

        hoverRange: function(e) {

            //ignore mouse movements while an above-calendar text input has focus
            if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
                return;

            var label = e.target.getAttribute('data-range-key');

            if (label == this.locale.customRangeLabel) {
                this.updateView();
            } else {
                var dates = this.ranges[label];
                this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format));
                this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format));
            }

        },

        clickRange: function(e) {
            var label = e.target.getAttribute('data-range-key');
            this.chosenLabel = label;
            if (label == this.locale.customRangeLabel) {
                this.showCalendars();
            } else {
                var dates = this.ranges[label];
                this.startDate = dates[0];
                this.endDate = dates[1];

                if (!this.timePicker) {
                    this.startDate.startOf('day');
                    this.endDate.endOf('day');
                }

                if (!this.alwaysShowCalendars)
                    this.hideCalendars();
                this.clickApply();
            }
        },

        clickPrev: function(e) {
            var cal = $(e.target).parents('.calendar');
            if (cal.hasClass('left')) {
                this.leftCalendar.month.subtract(1, 'month');
                if (this.linkedCalendars)
                    this.rightCalendar.month.subtract(1, 'month');
            } else {
                this.rightCalendar.month.subtract(1, 'month');
            }
            this.updateCalendars();
        },

        clickNext: function(e) {
            var cal = $(e.target).parents('.calendar');
            if (cal.hasClass('left')) {
                this.leftCalendar.month.add(1, 'month');
            } else {
                this.rightCalendar.month.add(1, 'month');
                if (this.linkedCalendars)
                    this.leftCalendar.month.add(1, 'month');
            }
            this.updateCalendars();
        },

        hoverDate: function(e) {

            //ignore mouse movements while an above-calendar text input has focus
            //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus"))
            //    return;

            //ignore dates that can't be selected
            if (!$(e.target).hasClass('available')) return;

            //have the text inputs above calendars reflect the date being hovered over
            var title = $(e.target).attr('data-title');
            var row = title.substr(1, 1);
            var col = title.substr(3, 1);
            var cal = $(e.target).parents('.calendar');
            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];

            if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) {
                this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format));
            } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) {
                this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format));
            }

            //highlight the dates between the start date and the date being hovered as a potential end date
            var leftCalendar = this.leftCalendar;
            var rightCalendar = this.rightCalendar;
            var startDate = this.startDate;
            if (!this.endDate) {
                this.container.find('.calendar tbody td').each(function(index, el) {

                    //skip week numbers, only look at dates
                    if ($(el).hasClass('week')) return;

                    var title = $(el).attr('data-title');
                    var row = title.substr(1, 1);
                    var col = title.substr(3, 1);
                    var cal = $(el).parents('.calendar');
                    var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col];

                    if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) {
                        $(el).addClass('in-range');
                    } else {
                        $(el).removeClass('in-range');
                    }

                });
            }

        },

        clickDate: function(e) {

            if (!$(e.target).hasClass('available')) return;

            var title = $(e.target).attr('data-title');
            var row = title.substr(1, 1);
            var col = title.substr(3, 1);
            var cal = $(e.target).parents('.calendar');
            var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col];

            //
            // this function needs to do a few things:
            // * alternate between selecting a start and end date for the range,
            // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date
            // * if autoapply is enabled, and an end date was chosen, apply the selection
            // * if single date picker mode, and time picker isn't enabled, apply the selection immediately
            // * if one of the inputs above the calendars was focused, cancel that manual input
            //

            if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start
                if (this.timePicker) {
                    var hour = parseInt(this.container.find('.left .hourselect').val(), 10);
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.left .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                    var minute = parseInt(this.container.find('.left .minuteselect').val(), 10);
                    var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0;
                    date = date.clone().hour(hour).minute(minute).second(second);
                }
                this.endDate = null;
                this.setStartDate(date.clone());
            } else if (!this.endDate && date.isBefore(this.startDate)) {
                //special case: clicking the same date for start/end,
                //but the time of the end date is before the start date
                this.setEndDate(this.startDate.clone());
            } else { // picking end
                if (this.timePicker) {
                    var hour = parseInt(this.container.find('.right .hourselect').val(), 10);
                    if (!this.timePicker24Hour) {
                        var ampm = this.container.find('.right .ampmselect').val();
                        if (ampm === 'PM' && hour < 12)
                            hour += 12;
                        if (ampm === 'AM' && hour === 12)
                            hour = 0;
                    }
                    var minute = parseInt(this.container.find('.right .minuteselect').val(), 10);
                    var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0;
                    date = date.clone().hour(hour).minute(minute).second(second);
                }
                this.setEndDate(date.clone());
                if (this.autoApply) {
                  this.calculateChosenLabel();
                  this.clickApply();
                }
            }

            if (this.singleDatePicker) {
                this.setEndDate(this.startDate);
                if (!this.timePicker)
                    this.clickApply();
            }

            this.updateView();

            //This is to cancel the blur event handler if the mouse was in one of the inputs
            e.stopPropagation();

        },

        calculateChosenLabel: function () {
            var customRange = true;
            var i = 0;
            for (var range in this.ranges) {
              if (this.timePicker) {
                    var format = this.timePickerSeconds ? "YYYY-MM-DD hh:mm:ss" : "YYYY-MM-DD hh:mm";
                    //ignore times when comparing dates if time picker seconds is not enabled
                    if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) {
                        customRange = false;
                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
                        break;
                    }
                } else {
                    //ignore times when comparing dates if time picker is not enabled
                    if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) {
                        customRange = false;
                        this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html();
                        break;
                    }
                }
                i++;
            }
            if (customRange) {
                if (this.showCustomRangeLabel) {
                    this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html();
                } else {
                    this.chosenLabel = null;
                }
                this.showCalendars();
            }
        },

        clickApply: function(e) {
            this.hide();
            this.element.trigger('apply.daterangepicker', this);
        },

        clickCancel: function(e) {
            this.startDate = this.oldStartDate;
            this.endDate = this.oldEndDate;
            this.hide();
            this.element.trigger('cancel.daterangepicker', this);
        },

        monthOrYearChanged: function(e) {
            var isLeft = $(e.target).closest('.calendar').hasClass('left'),
                leftOrRight = isLeft ? 'left' : 'right',
                cal = this.container.find('.calendar.'+leftOrRight);

            // Month must be Number for new moment versions
            var month = parseInt(cal.find('.monthselect').val(), 10);
            var year = cal.find('.yearselect').val();

            if (!isLeft) {
                if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) {
                    month = this.startDate.month();
                    year = this.startDate.year();
                }
            }

            if (this.minDate) {
                if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) {
                    month = this.minDate.month();
                    year = this.minDate.year();
                }
            }

            if (this.maxDate) {
                if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) {
                    month = this.maxDate.month();
                    year = this.maxDate.year();
                }
            }

            if (isLeft) {
                this.leftCalendar.month.month(month).year(year);
                if (this.linkedCalendars)
                    this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month');
            } else {
                this.rightCalendar.month.month(month).year(year);
                if (this.linkedCalendars)
                    this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month');
            }
            this.updateCalendars();
        },

        timeChanged: function(e) {

            var cal = $(e.target).closest('.calendar'),
                isLeft = cal.hasClass('left');

            var hour = parseInt(cal.find('.hourselect').val(), 10);
            var minute = parseInt(cal.find('.minuteselect').val(), 10);
            var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0;

            if (!this.timePicker24Hour) {
                var ampm = cal.find('.ampmselect').val();
                if (ampm === 'PM' && hour < 12)
                    hour += 12;
                if (ampm === 'AM' && hour === 12)
                    hour = 0;
            }

            if (isLeft) {
                var start = this.startDate.clone();
                start.hour(hour);
                start.minute(minute);
                start.second(second);
                this.setStartDate(start);
                if (this.singleDatePicker) {
                    this.endDate = this.startDate.clone();
                } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) {
                    this.setEndDate(start.clone());
                }
            } else if (this.endDate) {
                var end = this.endDate.clone();
                end.hour(hour);
                end.minute(minute);
                end.second(second);
                this.setEndDate(end);
            }

            //update the calendars so all clickable dates reflect the new time component
            this.updateCalendars();

            //update the form inputs above the calendars with the new time
            this.updateFormInputs();

            //re-render the time pickers because changing one selection can affect what's enabled in another
            this.renderTimePicker('left');
            this.renderTimePicker('right');

        },

        formInputsChanged: function(e) {
            var isRight = $(e.target).closest('.calendar').hasClass('right');
            var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format);
            var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format);

            if (start.isValid() && end.isValid()) {

                if (isRight && end.isBefore(start))
                    start = end.clone();

                this.setStartDate(start);
                this.setEndDate(end);

                if (isRight) {
                    this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format));
                } else {
                    this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format));
                }

            }

            this.updateView();
        },

        formInputsFocused: function(e) {

            // Highlight the focused input
            this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active');
            $(e.target).addClass('active');

            // Set the state such that if the user goes back to using a mouse, 
            // the calendars are aware we're selecting the end of the range, not
            // the start. This allows someone to edit the end of a date range without
            // re-selecting the beginning, by clicking on the end date input then
            // using the calendar.
            var isRight = $(e.target).closest('.calendar').hasClass('right');
            if (isRight) {
                this.endDate = null;
                this.setStartDate(this.startDate.clone());
                this.updateView();
            }

        },

        formInputsBlurred: function(e) {

            // this function has one purpose right now: if you tab from the first
            // text input to the second in the UI, the endDate is nulled so that
            // you can click another, but if you tab out without clicking anything
            // or changing the input value, the old endDate should be retained

            if (!this.endDate) {
                var val = this.container.find('input[name="daterangepicker_end"]').val();
                var end = moment(val, this.locale.format);
                if (end.isValid()) {
                    this.setEndDate(end);
                    this.updateView();
                }
            }

        },

        formInputsKeydown: function(e) {
            // This function ensures that if the 'enter' key was pressed in the input, then the calendars
            // are updated with the startDate and endDate.
            // This behaviour is automatic in Chrome/Firefox/Edge but not in IE 11 hence why this exists.
            // Other browsers and versions of IE are untested and the behaviour is unknown.
            if (e.keyCode === 13) {
                // Prevent the calendar from being updated twice on Chrome/Firefox/Edge
                e.preventDefault(); 
                this.formInputsChanged(e);
            }
        },


        elementChanged: function() {
            if (!this.element.is('input')) return;
            if (!this.element.val().length) return;

            var dateString = this.element.val().split(this.locale.separator),
                start = null,
                end = null;

            if (dateString.length === 2) {
                start = moment(dateString[0], this.locale.format);
                end = moment(dateString[1], this.locale.format);
            }

            if (this.singleDatePicker || start === null || end === null) {
                start = moment(this.element.val(), this.locale.format);
                end = start;
            }

            if (!start.isValid() || !end.isValid()) return;

            this.setStartDate(start);
            this.setEndDate(end);
            this.updateView();
        },

        keydown: function(e) {
            //hide on tab or enter
            if ((e.keyCode === 9) || (e.keyCode === 13)) {
                this.hide();
            }

            //hide on esc and prevent propagation
            if (e.keyCode === 27) {
                e.preventDefault();
                e.stopPropagation();

                this.hide();
            }
        },

        updateElement: function() {
            if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) {
                this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format));
                this.element.trigger('change');
            } else if (this.element.is('input') && this.autoUpdateInput) {
                this.element.val(this.startDate.format(this.locale.format));
                this.element.trigger('change');
            }
        },

        remove: function() {
            this.container.remove();
            this.element.off('.daterangepicker');
            this.element.removeData();
        }

    };

    $.fn.daterangepicker = function(options, callback) {
        var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options);
        this.each(function() {
            var el = $(this);
            if (el.data('daterangepicker'))
                el.data('daterangepicker').remove();
            el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback));
        });
        return this;
    };

    return DateRangePicker;

}));

},{"jquery":214,"moment":219}],201:[function(require,module,exports){
(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['module', 'select'], factory);
    } else if (typeof exports !== "undefined") {
        factory(module, require('select'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod, global.select);
        global.clipboardAction = mod.exports;
    }
})(this, function (module, _select) {
    'use strict';

    var _select2 = _interopRequireDefault(_select);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
        return typeof obj;
    } : function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    var ClipboardAction = function () {
        /**
         * @param {Object} options
         */
        function ClipboardAction(options) {
            _classCallCheck(this, ClipboardAction);

            this.resolveOptions(options);
            this.initSelection();
        }

        /**
         * Defines base properties passed from constructor.
         * @param {Object} options
         */


        _createClass(ClipboardAction, [{
            key: 'resolveOptions',
            value: function resolveOptions() {
                var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

                this.action = options.action;
                this.container = options.container;
                this.emitter = options.emitter;
                this.target = options.target;
                this.text = options.text;
                this.trigger = options.trigger;

                this.selectedText = '';
            }
        }, {
            key: 'initSelection',
            value: function initSelection() {
                if (this.text) {
                    this.selectFake();
                } else if (this.target) {
                    this.selectTarget();
                }
            }
        }, {
            key: 'selectFake',
            value: function selectFake() {
                var _this = this;

                var isRTL = document.documentElement.getAttribute('dir') == 'rtl';

                this.removeFake();

                this.fakeHandlerCallback = function () {
                    return _this.removeFake();
                };
                this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;

                this.fakeElem = document.createElement('textarea');
                // Prevent zooming on iOS
                this.fakeElem.style.fontSize = '12pt';
                // Reset box model
                this.fakeElem.style.border = '0';
                this.fakeElem.style.padding = '0';
                this.fakeElem.style.margin = '0';
                // Move element out of screen horizontally
                this.fakeElem.style.position = 'absolute';
                this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px';
                // Move element to the same position vertically
                var yPosition = window.pageYOffset || document.documentElement.scrollTop;
                this.fakeElem.style.top = yPosition + 'px';

                this.fakeElem.setAttribute('readonly', '');
                this.fakeElem.value = this.text;

                this.container.appendChild(this.fakeElem);

                this.selectedText = (0, _select2.default)(this.fakeElem);
                this.copyText();
            }
        }, {
            key: 'removeFake',
            value: function removeFake() {
                if (this.fakeHandler) {
                    this.container.removeEventListener('click', this.fakeHandlerCallback);
                    this.fakeHandler = null;
                    this.fakeHandlerCallback = null;
                }

                if (this.fakeElem) {
                    this.container.removeChild(this.fakeElem);
                    this.fakeElem = null;
                }
            }
        }, {
            key: 'selectTarget',
            value: function selectTarget() {
                this.selectedText = (0, _select2.default)(this.target);
                this.copyText();
            }
        }, {
            key: 'copyText',
            value: function copyText() {
                var succeeded = void 0;

                try {
                    succeeded = document.execCommand(this.action);
                } catch (err) {
                    succeeded = false;
                }

                this.handleResult(succeeded);
            }
        }, {
            key: 'handleResult',
            value: function handleResult(succeeded) {
                this.emitter.emit(succeeded ? 'success' : 'error', {
                    action: this.action,
                    text: this.selectedText,
                    trigger: this.trigger,
                    clearSelection: this.clearSelection.bind(this)
                });
            }
        }, {
            key: 'clearSelection',
            value: function clearSelection() {
                if (this.trigger) {
                    this.trigger.focus();
                }

                window.getSelection().removeAllRanges();
            }
        }, {
            key: 'destroy',
            value: function destroy() {
                this.removeFake();
            }
        }, {
            key: 'action',
            set: function set() {
                var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';

                this._action = action;

                if (this._action !== 'copy' && this._action !== 'cut') {
                    throw new Error('Invalid "action" value, use either "copy" or "cut"');
                }
            },
            get: function get() {
                return this._action;
            }
        }, {
            key: 'target',
            set: function set(target) {
                if (target !== undefined) {
                    if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {
                        if (this.action === 'copy' && target.hasAttribute('disabled')) {
                            throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
                        }

                        if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {
                            throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
                        }

                        this._target = target;
                    } else {
                        throw new Error('Invalid "target" value, use a valid Element');
                    }
                }
            },
            get: function get() {
                return this._target;
            }
        }]);

        return ClipboardAction;
    }();

    module.exports = ClipboardAction;
});
},{"select":224}],202:[function(require,module,exports){
(function (global, factory) {
    if (typeof define === "function" && define.amd) {
        define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory);
    } else if (typeof exports !== "undefined") {
        factory(module, require('./clipboard-action'), require('tiny-emitter'), require('good-listener'));
    } else {
        var mod = {
            exports: {}
        };
        factory(mod, global.clipboardAction, global.tinyEmitter, global.goodListener);
        global.clipboard = mod.exports;
    }
})(this, function (module, _clipboardAction, _tinyEmitter, _goodListener) {
    'use strict';

    var _clipboardAction2 = _interopRequireDefault(_clipboardAction);

    var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);

    var _goodListener2 = _interopRequireDefault(_goodListener);

    function _interopRequireDefault(obj) {
        return obj && obj.__esModule ? obj : {
            default: obj
        };
    }

    var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
        return typeof obj;
    } : function (obj) {
        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
    };

    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) {
            throw new TypeError("Cannot call a class as a function");
        }
    }

    var _createClass = function () {
        function defineProperties(target, props) {
            for (var i = 0; i < props.length; i++) {
                var descriptor = props[i];
                descriptor.enumerable = descriptor.enumerable || false;
                descriptor.configurable = true;
                if ("value" in descriptor) descriptor.writable = true;
                Object.defineProperty(target, descriptor.key, descriptor);
            }
        }

        return function (Constructor, protoProps, staticProps) {
            if (protoProps) defineProperties(Constructor.prototype, protoProps);
            if (staticProps) defineProperties(Constructor, staticProps);
            return Constructor;
        };
    }();

    function _possibleConstructorReturn(self, call) {
        if (!self) {
            throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
        }

        return call && (typeof call === "object" || typeof call === "function") ? call : self;
    }

    function _inherits(subClass, superClass) {
        if (typeof superClass !== "function" && superClass !== null) {
            throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
        }

        subClass.prototype = Object.create(superClass && superClass.prototype, {
            constructor: {
                value: subClass,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
    }

    var Clipboard = function (_Emitter) {
        _inherits(Clipboard, _Emitter);

        /**
         * @param {String|HTMLElement|HTMLCollection|NodeList} trigger
         * @param {Object} options
         */
        function Clipboard(trigger, options) {
            _classCallCheck(this, Clipboard);

            var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));

            _this.resolveOptions(options);
            _this.listenClick(trigger);
            return _this;
        }

        /**
         * Defines if attributes would be resolved using internal setter functions
         * or custom functions that were passed in the constructor.
         * @param {Object} options
         */


        _createClass(Clipboard, [{
            key: 'resolveOptions',
            value: function resolveOptions() {
                var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

                this.action = typeof options.action === 'function' ? options.action : this.defaultAction;
                this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;
                this.text = typeof options.text === 'function' ? options.text : this.defaultText;
                this.container = _typeof(options.container) === 'object' ? options.container : document.body;
            }
        }, {
            key: 'listenClick',
            value: function listenClick(trigger) {
                var _this2 = this;

                this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {
                    return _this2.onClick(e);
                });
            }
        }, {
            key: 'onClick',
            value: function onClick(e) {
                var trigger = e.delegateTarget || e.currentTarget;

                if (this.clipboardAction) {
                    this.clipboardAction = null;
                }

                this.clipboardAction = new _clipboardAction2.default({
                    action: this.action(trigger),
                    target: this.target(trigger),
                    text: this.text(trigger),
                    container: this.container,
                    trigger: trigger,
                    emitter: this
                });
            }
        }, {
            key: 'defaultAction',
            value: function defaultAction(trigger) {
                return getAttributeValue('action', trigger);
            }
        }, {
            key: 'defaultTarget',
            value: function defaultTarget(trigger) {
                var selector = getAttributeValue('target', trigger);

                if (selector) {
                    return document.querySelector(selector);
                }
            }
        }, {
            key: 'defaultText',
            value: function defaultText(trigger) {
                return getAttributeValue('text', trigger);
            }
        }, {
            key: 'destroy',
            value: function destroy() {
                this.listener.destroy();

                if (this.clipboardAction) {
                    this.clipboardAction.destroy();
                    this.clipboardAction = null;
                }
            }
        }], [{
            key: 'isSupported',
            value: function isSupported() {
                var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];

                var actions = typeof action === 'string' ? [action] : action;
                var support = !!document.queryCommandSupported;

                actions.forEach(function (action) {
                    support = support && !!document.queryCommandSupported(action);
                });

                return support;
            }
        }]);

        return Clipboard;
    }(_tinyEmitter2.default);

    /**
     * Helper function to retrieve attribute value.
     * @param {String} suffix
     * @param {Element} element
     */
    function getAttributeValue(suffix, element) {
        var attribute = 'data-clipboard-' + suffix;

        if (!element.hasAttribute(attribute)) {
            return;
        }

        return element.getAttribute(attribute);
    }

    module.exports = Clipboard;
});
},{"./clipboard-action":201,"good-listener":211,"tiny-emitter":226}],203:[function(require,module,exports){
var DOCUMENT_NODE_TYPE = 9;

/**
 * A polyfill for Element.matches()
 */
if (typeof Element !== 'undefined' && !Element.prototype.matches) {
    var proto = Element.prototype;

    proto.matches = proto.matchesSelector ||
                    proto.mozMatchesSelector ||
                    proto.msMatchesSelector ||
                    proto.oMatchesSelector ||
                    proto.webkitMatchesSelector;
}

/**
 * Finds the closest parent that matches a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @return {Function}
 */
function closest (element, selector) {
    while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {
        if (typeof element.matches === 'function' &&
            element.matches(selector)) {
          return element;
        }
        element = element.parentNode;
    }
}

module.exports = closest;

},{}],204:[function(require,module,exports){
var closest = require('./closest');

/**
 * Delegates event to a selector.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @param {Boolean} useCapture
 * @return {Object}
 */
function _delegate(element, selector, type, callback, useCapture) {
    var listenerFn = listener.apply(this, arguments);

    element.addEventListener(type, listenerFn, useCapture);

    return {
        destroy: function() {
            element.removeEventListener(type, listenerFn, useCapture);
        }
    }
}

/**
 * Delegates event to a selector.
 *
 * @param {Element|String|Array} [elements]
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @param {Boolean} useCapture
 * @return {Object}
 */
function delegate(elements, selector, type, callback, useCapture) {
    // Handle the regular Element usage
    if (typeof elements.addEventListener === 'function') {
        return _delegate.apply(null, arguments);
    }

    // Handle Element-less usage, it defaults to global delegation
    if (typeof type === 'function') {
        // Use `document` as the first parameter, then apply arguments
        // This is a short way to .unshift `arguments` without running into deoptimizations
        return _delegate.bind(null, document).apply(null, arguments);
    }

    // Handle Selector-based usage
    if (typeof elements === 'string') {
        elements = document.querySelectorAll(elements);
    }

    // Handle Array-like based usage
    return Array.prototype.map.call(elements, function (element) {
        return _delegate(element, selector, type, callback, useCapture);
    });
}

/**
 * Finds closest match and invokes callback.
 *
 * @param {Element} element
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @return {Function}
 */
function listener(element, selector, type, callback) {
    return function(e) {
        e.delegateTarget = closest(e.target, selector);

        if (e.delegateTarget) {
            callback.call(element, e);
        }
    }
}

module.exports = delegate;

},{"./closest":203}],205:[function(require,module,exports){
/**
 * matchesSelector v2.0.2
 * matchesSelector( element, '.selector' )
 * MIT license
 */

/*jshint browser: true, strict: true, undef: true, unused: true */

( function( window, factory ) {
  /*global define: false, module: false */
  'use strict';
  // universal module definition
  if ( typeof define == 'function' && define.amd ) {
    // AMD
    define( factory );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS
    module.exports = factory();
  } else {
    // browser global
    window.matchesSelector = factory();
  }

}( window, function factory() {
  'use strict';

  var matchesMethod = ( function() {
    var ElemProto = window.Element.prototype;
    // check for the standard method name first
    if ( ElemProto.matches ) {
      return 'matches';
    }
    // check un-prefixed
    if ( ElemProto.matchesSelector ) {
      return 'matchesSelector';
    }
    // check vendor prefixes
    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];

    for ( var i=0; i < prefixes.length; i++ ) {
      var prefix = prefixes[i];
      var method = prefix + 'MatchesSelector';
      if ( ElemProto[ method ] ) {
        return method;
      }
    }
  })();

  return function matchesSelector( elem, selector ) {
    return elem[ matchesMethod ]( selector );
  };

}));

},{}],206:[function(require,module,exports){
(function (global,setImmediate){
/*
 * Dexie.js - a minimalistic wrapper for IndexedDB
 * ===============================================
 *
 * By David Fahlander, david.fahlander@gmail.com
 *
 * Version 4.0.11, Wed Jan 15 2025
 *
 * https://dexie.org
 *
 * Apache License Version 2.0, January 2004, http://www.apache.org/licenses/
 */
 
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Dexie = factory());
})(this, (function () { 'use strict';

    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation.
    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.
    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */
    var extendStatics = function(d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    function __extends(d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    }
    var __assign = function() {
        __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
        return __assign.apply(this, arguments);
    };
    function __spreadArray(to, from, pack) {
        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
            if (ar || !(i in from)) {
                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
                ar[i] = from[i];
            }
        }
        return to.concat(ar || Array.prototype.slice.call(from));
    }

    var _global = typeof globalThis !== 'undefined' ? globalThis :
        typeof self !== 'undefined' ? self :
            typeof window !== 'undefined' ? window :
                global;

    var keys = Object.keys;
    var isArray = Array.isArray;
    if (typeof Promise !== 'undefined' && !_global.Promise) {
        _global.Promise = Promise;
    }
    function extend(obj, extension) {
        if (typeof extension !== 'object')
            return obj;
        keys(extension).forEach(function (key) {
            obj[key] = extension[key];
        });
        return obj;
    }
    var getProto = Object.getPrototypeOf;
    var _hasOwn = {}.hasOwnProperty;
    function hasOwn(obj, prop) {
        return _hasOwn.call(obj, prop);
    }
    function props(proto, extension) {
        if (typeof extension === 'function')
            extension = extension(getProto(proto));
        (typeof Reflect === "undefined" ? keys : Reflect.ownKeys)(extension).forEach(function (key) {
            setProp(proto, key, extension[key]);
        });
    }
    var defineProperty = Object.defineProperty;
    function setProp(obj, prop, functionOrGetSet, options) {
        defineProperty(obj, prop, extend(functionOrGetSet && hasOwn(functionOrGetSet, "get") && typeof functionOrGetSet.get === 'function' ?
            { get: functionOrGetSet.get, set: functionOrGetSet.set, configurable: true } :
            { value: functionOrGetSet, configurable: true, writable: true }, options));
    }
    function derive(Child) {
        return {
            from: function (Parent) {
                Child.prototype = Object.create(Parent.prototype);
                setProp(Child.prototype, "constructor", Child);
                return {
                    extend: props.bind(null, Child.prototype)
                };
            }
        };
    }
    var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
    function getPropertyDescriptor(obj, prop) {
        var pd = getOwnPropertyDescriptor(obj, prop);
        var proto;
        return pd || (proto = getProto(obj)) && getPropertyDescriptor(proto, prop);
    }
    var _slice = [].slice;
    function slice(args, start, end) {
        return _slice.call(args, start, end);
    }
    function override(origFunc, overridedFactory) {
        return overridedFactory(origFunc);
    }
    function assert(b) {
        if (!b)
            throw new Error("Assertion Failed");
    }
    function asap$1(fn) {
        if (_global.setImmediate)
            setImmediate(fn);
        else
            setTimeout(fn, 0);
    }
    function arrayToObject(array, extractor) {
        return array.reduce(function (result, item, i) {
            var nameAndValue = extractor(item, i);
            if (nameAndValue)
                result[nameAndValue[0]] = nameAndValue[1];
            return result;
        }, {});
    }
    function getByKeyPath(obj, keyPath) {
        if (typeof keyPath === 'string' && hasOwn(obj, keyPath))
            return obj[keyPath];
        if (!keyPath)
            return obj;
        if (typeof keyPath !== 'string') {
            var rv = [];
            for (var i = 0, l = keyPath.length; i < l; ++i) {
                var val = getByKeyPath(obj, keyPath[i]);
                rv.push(val);
            }
            return rv;
        }
        var period = keyPath.indexOf('.');
        if (period !== -1) {
            var innerObj = obj[keyPath.substr(0, period)];
            return innerObj == null ? undefined : getByKeyPath(innerObj, keyPath.substr(period + 1));
        }
        return undefined;
    }
    function setByKeyPath(obj, keyPath, value) {
        if (!obj || keyPath === undefined)
            return;
        if ('isFrozen' in Object && Object.isFrozen(obj))
            return;
        if (typeof keyPath !== 'string' && 'length' in keyPath) {
            assert(typeof value !== 'string' && 'length' in value);
            for (var i = 0, l = keyPath.length; i < l; ++i) {
                setByKeyPath(obj, keyPath[i], value[i]);
            }
        }
        else {
            var period = keyPath.indexOf('.');
            if (period !== -1) {
                var currentKeyPath = keyPath.substr(0, period);
                var remainingKeyPath = keyPath.substr(period + 1);
                if (remainingKeyPath === "")
                    if (value === undefined) {
                        if (isArray(obj) && !isNaN(parseInt(currentKeyPath)))
                            obj.splice(currentKeyPath, 1);
                        else
                            delete obj[currentKeyPath];
                    }
                    else
                        obj[currentKeyPath] = value;
                else {
                    var innerObj = obj[currentKeyPath];
                    if (!innerObj || !hasOwn(obj, currentKeyPath))
                        innerObj = (obj[currentKeyPath] = {});
                    setByKeyPath(innerObj, remainingKeyPath, value);
                }
            }
            else {
                if (value === undefined) {
                    if (isArray(obj) && !isNaN(parseInt(keyPath)))
                        obj.splice(keyPath, 1);
                    else
                        delete obj[keyPath];
                }
                else
                    obj[keyPath] = value;
            }
        }
    }
    function delByKeyPath(obj, keyPath) {
        if (typeof keyPath === 'string')
            setByKeyPath(obj, keyPath, undefined);
        else if ('length' in keyPath)
            [].map.call(keyPath, function (kp) {
                setByKeyPath(obj, kp, undefined);
            });
    }
    function shallowClone(obj) {
        var rv = {};
        for (var m in obj) {
            if (hasOwn(obj, m))
                rv[m] = obj[m];
        }
        return rv;
    }
    var concat = [].concat;
    function flatten(a) {
        return concat.apply([], a);
    }
    var intrinsicTypeNames = "BigUint64Array,BigInt64Array,Array,Boolean,String,Date,RegExp,Blob,File,FileList,FileSystemFileHandle,FileSystemDirectoryHandle,ArrayBuffer,DataView,Uint8ClampedArray,ImageBitmap,ImageData,Map,Set,CryptoKey"
        .split(',').concat(flatten([8, 16, 32, 64].map(function (num) { return ["Int", "Uint", "Float"].map(function (t) { return t + num + "Array"; }); }))).filter(function (t) { return _global[t]; });
    var intrinsicTypes = new Set(intrinsicTypeNames.map(function (t) { return _global[t]; }));
    function cloneSimpleObjectTree(o) {
        var rv = {};
        for (var k in o)
            if (hasOwn(o, k)) {
                var v = o[k];
                rv[k] = !v || typeof v !== 'object' || intrinsicTypes.has(v.constructor) ? v : cloneSimpleObjectTree(v);
            }
        return rv;
    }
    function objectIsEmpty(o) {
        for (var k in o)
            if (hasOwn(o, k))
                return false;
        return true;
    }
    var circularRefs = null;
    function deepClone(any) {
        circularRefs = new WeakMap();
        var rv = innerDeepClone(any);
        circularRefs = null;
        return rv;
    }
    function innerDeepClone(x) {
        if (!x || typeof x !== 'object')
            return x;
        var rv = circularRefs.get(x);
        if (rv)
            return rv;
        if (isArray(x)) {
            rv = [];
            circularRefs.set(x, rv);
            for (var i = 0, l = x.length; i < l; ++i) {
                rv.push(innerDeepClone(x[i]));
            }
        }
        else if (intrinsicTypes.has(x.constructor)) {
            rv = x;
        }
        else {
            var proto = getProto(x);
            rv = proto === Object.prototype ? {} : Object.create(proto);
            circularRefs.set(x, rv);
            for (var prop in x) {
                if (hasOwn(x, prop)) {
                    rv[prop] = innerDeepClone(x[prop]);
                }
            }
        }
        return rv;
    }
    var toString = {}.toString;
    function toStringTag(o) {
        return toString.call(o).slice(8, -1);
    }
    var iteratorSymbol = typeof Symbol !== 'undefined' ?
        Symbol.iterator :
        '@@iterator';
    var getIteratorOf = typeof iteratorSymbol === "symbol" ? function (x) {
        var i;
        return x != null && (i = x[iteratorSymbol]) && i.apply(x);
    } : function () { return null; };
    function delArrayItem(a, x) {
        var i = a.indexOf(x);
        if (i >= 0)
            a.splice(i, 1);
        return i >= 0;
    }
    var NO_CHAR_ARRAY = {};
    function getArrayOf(arrayLike) {
        var i, a, x, it;
        if (arguments.length === 1) {
            if (isArray(arrayLike))
                return arrayLike.slice();
            if (this === NO_CHAR_ARRAY && typeof arrayLike === 'string')
                return [arrayLike];
            if ((it = getIteratorOf(arrayLike))) {
                a = [];
                while ((x = it.next()), !x.done)
                    a.push(x.value);
                return a;
            }
            if (arrayLike == null)
                return [arrayLike];
            i = arrayLike.length;
            if (typeof i === 'number') {
                a = new Array(i);
                while (i--)
                    a[i] = arrayLike[i];
                return a;
            }
            return [arrayLike];
        }
        i = arguments.length;
        a = new Array(i);
        while (i--)
            a[i] = arguments[i];
        return a;
    }
    var isAsyncFunction = typeof Symbol !== 'undefined'
        ? function (fn) { return fn[Symbol.toStringTag] === 'AsyncFunction'; }
        : function () { return false; };

    var dexieErrorNames = [
        'Modify',
        'Bulk',
        'OpenFailed',
        'VersionChange',
        'Schema',
        'Upgrade',
        'InvalidTable',
        'MissingAPI',
        'NoSuchDatabase',
        'InvalidArgument',
        'SubTransaction',
        'Unsupported',
        'Internal',
        'DatabaseClosed',
        'PrematureCommit',
        'ForeignAwait'
    ];
    var idbDomErrorNames = [
        'Unknown',
        'Constraint',
        'Data',
        'TransactionInactive',
        'ReadOnly',
        'Version',
        'NotFound',
        'InvalidState',
        'InvalidAccess',
        'Abort',
        'Timeout',
        'QuotaExceeded',
        'Syntax',
        'DataClone'
    ];
    var errorList = dexieErrorNames.concat(idbDomErrorNames);
    var defaultTexts = {
        VersionChanged: "Database version changed by other database connection",
        DatabaseClosed: "Database has been closed",
        Abort: "Transaction aborted",
        TransactionInactive: "Transaction has already completed or failed",
        MissingAPI: "IndexedDB API missing. Please visit https://tinyurl.com/y2uuvskb"
    };
    function DexieError(name, msg) {
        this.name = name;
        this.message = msg;
    }
    derive(DexieError).from(Error).extend({
        toString: function () { return this.name + ": " + this.message; }
    });
    function getMultiErrorMessage(msg, failures) {
        return msg + ". Errors: " + Object.keys(failures)
            .map(function (key) { return failures[key].toString(); })
            .filter(function (v, i, s) { return s.indexOf(v) === i; })
            .join('\n');
    }
    function ModifyError(msg, failures, successCount, failedKeys) {
        this.failures = failures;
        this.failedKeys = failedKeys;
        this.successCount = successCount;
        this.message = getMultiErrorMessage(msg, failures);
    }
    derive(ModifyError).from(DexieError);
    function BulkError(msg, failures) {
        this.name = "BulkError";
        this.failures = Object.keys(failures).map(function (pos) { return failures[pos]; });
        this.failuresByPos = failures;
        this.message = getMultiErrorMessage(msg, this.failures);
    }
    derive(BulkError).from(DexieError);
    var errnames = errorList.reduce(function (obj, name) { return (obj[name] = name + "Error", obj); }, {});
    var BaseException = DexieError;
    var exceptions = errorList.reduce(function (obj, name) {
        var fullName = name + "Error";
        function DexieError(msgOrInner, inner) {
            this.name = fullName;
            if (!msgOrInner) {
                this.message = defaultTexts[name] || fullName;
                this.inner = null;
            }
            else if (typeof msgOrInner === 'string') {
                this.message = "".concat(msgOrInner).concat(!inner ? '' : '\n ' + inner);
                this.inner = inner || null;
            }
            else if (typeof msgOrInner === 'object') {
                this.message = "".concat(msgOrInner.name, " ").concat(msgOrInner.message);
                this.inner = msgOrInner;
            }
        }
        derive(DexieError).from(BaseException);
        obj[name] = DexieError;
        return obj;
    }, {});
    exceptions.Syntax = SyntaxError;
    exceptions.Type = TypeError;
    exceptions.Range = RangeError;
    var exceptionMap = idbDomErrorNames.reduce(function (obj, name) {
        obj[name + "Error"] = exceptions[name];
        return obj;
    }, {});
    function mapError(domError, message) {
        if (!domError || domError instanceof DexieError || domError instanceof TypeError || domError instanceof SyntaxError || !domError.name || !exceptionMap[domError.name])
            return domError;
        var rv = new exceptionMap[domError.name](message || domError.message, domError);
        if ("stack" in domError) {
            setProp(rv, "stack", { get: function () {
                    return this.inner.stack;
                } });
        }
        return rv;
    }
    var fullNameExceptions = errorList.reduce(function (obj, name) {
        if (["Syntax", "Type", "Range"].indexOf(name) === -1)
            obj[name + "Error"] = exceptions[name];
        return obj;
    }, {});
    fullNameExceptions.ModifyError = ModifyError;
    fullNameExceptions.DexieError = DexieError;
    fullNameExceptions.BulkError = BulkError;

    function nop() { }
    function mirror(val) { return val; }
    function pureFunctionChain(f1, f2) {
        if (f1 == null || f1 === mirror)
            return f2;
        return function (val) {
            return f2(f1(val));
        };
    }
    function callBoth(on1, on2) {
        return function () {
            on1.apply(this, arguments);
            on2.apply(this, arguments);
        };
    }
    function hookCreatingChain(f1, f2) {
        if (f1 === nop)
            return f2;
        return function () {
            var res = f1.apply(this, arguments);
            if (res !== undefined)
                arguments[0] = res;
            var onsuccess = this.onsuccess,
            onerror = this.onerror;
            this.onsuccess = null;
            this.onerror = null;
            var res2 = f2.apply(this, arguments);
            if (onsuccess)
                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
            if (onerror)
                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
            return res2 !== undefined ? res2 : res;
        };
    }
    function hookDeletingChain(f1, f2) {
        if (f1 === nop)
            return f2;
        return function () {
            f1.apply(this, arguments);
            var onsuccess = this.onsuccess,
            onerror = this.onerror;
            this.onsuccess = this.onerror = null;
            f2.apply(this, arguments);
            if (onsuccess)
                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
            if (onerror)
                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
        };
    }
    function hookUpdatingChain(f1, f2) {
        if (f1 === nop)
            return f2;
        return function (modifications) {
            var res = f1.apply(this, arguments);
            extend(modifications, res);
            var onsuccess = this.onsuccess,
            onerror = this.onerror;
            this.onsuccess = null;
            this.onerror = null;
            var res2 = f2.apply(this, arguments);
            if (onsuccess)
                this.onsuccess = this.onsuccess ? callBoth(onsuccess, this.onsuccess) : onsuccess;
            if (onerror)
                this.onerror = this.onerror ? callBoth(onerror, this.onerror) : onerror;
            return res === undefined ?
                (res2 === undefined ? undefined : res2) :
                (extend(res, res2));
        };
    }
    function reverseStoppableEventChain(f1, f2) {
        if (f1 === nop)
            return f2;
        return function () {
            if (f2.apply(this, arguments) === false)
                return false;
            return f1.apply(this, arguments);
        };
    }
    function promisableChain(f1, f2) {
        if (f1 === nop)
            return f2;
        return function () {
            var res = f1.apply(this, arguments);
            if (res && typeof res.then === 'function') {
                var thiz = this, i = arguments.length, args = new Array(i);
                while (i--)
                    args[i] = arguments[i];
                return res.then(function () {
                    return f2.apply(thiz, args);
                });
            }
            return f2.apply(this, arguments);
        };
    }

    var debug = typeof location !== 'undefined' &&
        /^(http|https):\/\/(localhost|127\.0\.0\.1)/.test(location.href);
    function setDebug(value, filter) {
        debug = value;
    }

    var INTERNAL = {};
    var ZONE_ECHO_LIMIT = 100, _a$1 = typeof Promise === 'undefined' ?
        [] :
        (function () {
            var globalP = Promise.resolve();
            if (typeof crypto === 'undefined' || !crypto.subtle)
                return [globalP, getProto(globalP), globalP];
            var nativeP = crypto.subtle.digest("SHA-512", new Uint8Array([0]));
            return [
                nativeP,
                getProto(nativeP),
                globalP
            ];
        })(), resolvedNativePromise = _a$1[0], nativePromiseProto = _a$1[1], resolvedGlobalPromise = _a$1[2], nativePromiseThen = nativePromiseProto && nativePromiseProto.then;
    var NativePromise = resolvedNativePromise && resolvedNativePromise.constructor;
    var patchGlobalPromise = !!resolvedGlobalPromise;
    function schedulePhysicalTick() {
        queueMicrotask(physicalTick);
    }
    var asap = function (callback, args) {
        microtickQueue.push([callback, args]);
        if (needsNewPhysicalTick) {
            schedulePhysicalTick();
            needsNewPhysicalTick = false;
        }
    };
    var isOutsideMicroTick = true,
    needsNewPhysicalTick = true,
    unhandledErrors = [],
    rejectingErrors = [],
    rejectionMapper = mirror;
    var globalPSD = {
        id: 'global',
        global: true,
        ref: 0,
        unhandleds: [],
        onunhandled: nop,
        pgp: false,
        env: {},
        finalize: nop
    };
    var PSD = globalPSD;
    var microtickQueue = [];
    var numScheduledCalls = 0;
    var tickFinalizers = [];
    function DexiePromise(fn) {
        if (typeof this !== 'object')
            throw new TypeError('Promises must be constructed via new');
        this._listeners = [];
        this._lib = false;
        var psd = (this._PSD = PSD);
        if (typeof fn !== 'function') {
            if (fn !== INTERNAL)
                throw new TypeError('Not a function');
            this._state = arguments[1];
            this._value = arguments[2];
            if (this._state === false)
                handleRejection(this, this._value);
            return;
        }
        this._state = null;
        this._value = null;
        ++psd.ref;
        executePromiseTask(this, fn);
    }
    var thenProp = {
        get: function () {
            var psd = PSD, microTaskId = totalEchoes;
            function then(onFulfilled, onRejected) {
                var _this = this;
                var possibleAwait = !psd.global && (psd !== PSD || microTaskId !== totalEchoes);
                var cleanup = possibleAwait && !decrementExpectedAwaits();
                var rv = new DexiePromise(function (resolve, reject) {
                    propagateToListener(_this, new Listener(nativeAwaitCompatibleWrap(onFulfilled, psd, possibleAwait, cleanup), nativeAwaitCompatibleWrap(onRejected, psd, possibleAwait, cleanup), resolve, reject, psd));
                });
                if (this._consoleTask)
                    rv._consoleTask = this._consoleTask;
                return rv;
            }
            then.prototype = INTERNAL;
            return then;
        },
        set: function (value) {
            setProp(this, 'then', value && value.prototype === INTERNAL ?
                thenProp :
                {
                    get: function () {
                        return value;
                    },
                    set: thenProp.set
                });
        }
    };
    props(DexiePromise.prototype, {
        then: thenProp,
        _then: function (onFulfilled, onRejected) {
            propagateToListener(this, new Listener(null, null, onFulfilled, onRejected, PSD));
        },
        catch: function (onRejected) {
            if (arguments.length === 1)
                return this.then(null, onRejected);
            var type = arguments[0], handler = arguments[1];
            return typeof type === 'function' ? this.then(null, function (err) {
                return err instanceof type ? handler(err) : PromiseReject(err);
            })
                : this.then(null, function (err) {
                    return err && err.name === type ? handler(err) : PromiseReject(err);
                });
        },
        finally: function (onFinally) {
            return this.then(function (value) {
                return DexiePromise.resolve(onFinally()).then(function () { return value; });
            }, function (err) {
                return DexiePromise.resolve(onFinally()).then(function () { return PromiseReject(err); });
            });
        },
        timeout: function (ms, msg) {
            var _this = this;
            return ms < Infinity ?
                new DexiePromise(function (resolve, reject) {
                    var handle = setTimeout(function () { return reject(new exceptions.Timeout(msg)); }, ms);
                    _this.then(resolve, reject).finally(clearTimeout.bind(null, handle));
                }) : this;
        }
    });
    if (typeof Symbol !== 'undefined' && Symbol.toStringTag)
        setProp(DexiePromise.prototype, Symbol.toStringTag, 'Dexie.Promise');
    globalPSD.env = snapShot();
    function Listener(onFulfilled, onRejected, resolve, reject, zone) {
        this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
        this.onRejected = typeof onRejected === 'function' ? onRejected : null;
        this.resolve = resolve;
        this.reject = reject;
        this.psd = zone;
    }
    props(DexiePromise, {
        all: function () {
            var values = getArrayOf.apply(null, arguments)
                .map(onPossibleParallellAsync);
            return new DexiePromise(function (resolve, reject) {
                if (values.length === 0)
                    resolve([]);
                var remaining = values.length;
                values.forEach(function (a, i) { return DexiePromise.resolve(a).then(function (x) {
                    values[i] = x;
                    if (!--remaining)
                        resolve(values);
                }, reject); });
            });
        },
        resolve: function (value) {
            if (value instanceof DexiePromise)
                return value;
            if (value && typeof value.then === 'function')
                return new DexiePromise(function (resolve, reject) {
                    value.then(resolve, reject);
                });
            var rv = new DexiePromise(INTERNAL, true, value);
            return rv;
        },
        reject: PromiseReject,
        race: function () {
            var values = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
            return new DexiePromise(function (resolve, reject) {
                values.map(function (value) { return DexiePromise.resolve(value).then(resolve, reject); });
            });
        },
        PSD: {
            get: function () { return PSD; },
            set: function (value) { return PSD = value; }
        },
        totalEchoes: { get: function () { return totalEchoes; } },
        newPSD: newScope,
        usePSD: usePSD,
        scheduler: {
            get: function () { return asap; },
            set: function (value) { asap = value; }
        },
        rejectionMapper: {
            get: function () { return rejectionMapper; },
            set: function (value) { rejectionMapper = value; }
        },
        follow: function (fn, zoneProps) {
            return new DexiePromise(function (resolve, reject) {
                return newScope(function (resolve, reject) {
                    var psd = PSD;
                    psd.unhandleds = [];
                    psd.onunhandled = reject;
                    psd.finalize = callBoth(function () {
                        var _this = this;
                        run_at_end_of_this_or_next_physical_tick(function () {
                            _this.unhandleds.length === 0 ? resolve() : reject(_this.unhandleds[0]);
                        });
                    }, psd.finalize);
                    fn();
                }, zoneProps, resolve, reject);
            });
        }
    });
    if (NativePromise) {
        if (NativePromise.allSettled)
            setProp(DexiePromise, "allSettled", function () {
                var possiblePromises = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
                return new DexiePromise(function (resolve) {
                    if (possiblePromises.length === 0)
                        resolve([]);
                    var remaining = possiblePromises.length;
                    var results = new Array(remaining);
                    possiblePromises.forEach(function (p, i) { return DexiePromise.resolve(p).then(function (value) { return results[i] = { status: "fulfilled", value: value }; }, function (reason) { return results[i] = { status: "rejected", reason: reason }; })
                        .then(function () { return --remaining || resolve(results); }); });
                });
            });
        if (NativePromise.any && typeof AggregateError !== 'undefined')
            setProp(DexiePromise, "any", function () {
                var possiblePromises = getArrayOf.apply(null, arguments).map(onPossibleParallellAsync);
                return new DexiePromise(function (resolve, reject) {
                    if (possiblePromises.length === 0)
                        reject(new AggregateError([]));
                    var remaining = possiblePromises.length;
                    var failures = new Array(remaining);
                    possiblePromises.forEach(function (p, i) { return DexiePromise.resolve(p).then(function (value) { return resolve(value); }, function (failure) {
                        failures[i] = failure;
                        if (!--remaining)
                            reject(new AggregateError(failures));
                    }); });
                });
            });
        if (NativePromise.withResolvers)
            DexiePromise.withResolvers = NativePromise.withResolvers;
    }
    function executePromiseTask(promise, fn) {
        try {
            fn(function (value) {
                if (promise._state !== null)
                    return;
                if (value === promise)
                    throw new TypeError('A promise cannot be resolved with itself.');
                var shouldExecuteTick = promise._lib && beginMicroTickScope();
                if (value && typeof value.then === 'function') {
                    executePromiseTask(promise, function (resolve, reject) {
                        value instanceof DexiePromise ?
                            value._then(resolve, reject) :
                            value.then(resolve, reject);
                    });
                }
                else {
                    promise._state = true;
                    promise._value = value;
                    propagateAllListeners(promise);
                }
                if (shouldExecuteTick)
                    endMicroTickScope();
            }, handleRejection.bind(null, promise));
        }
        catch (ex) {
            handleRejection(promise, ex);
        }
    }
    function handleRejection(promise, reason) {
        rejectingErrors.push(reason);
        if (promise._state !== null)
            return;
        var shouldExecuteTick = promise._lib && beginMicroTickScope();
        reason = rejectionMapper(reason);
        promise._state = false;
        promise._value = reason;
        addPossiblyUnhandledError(promise);
        propagateAllListeners(promise);
        if (shouldExecuteTick)
            endMicroTickScope();
    }
    function propagateAllListeners(promise) {
        var listeners = promise._listeners;
        promise._listeners = [];
        for (var i = 0, len = listeners.length; i < len; ++i) {
            propagateToListener(promise, listeners[i]);
        }
        var psd = promise._PSD;
        --psd.ref || psd.finalize();
        if (numScheduledCalls === 0) {
            ++numScheduledCalls;
            asap(function () {
                if (--numScheduledCalls === 0)
                    finalizePhysicalTick();
            }, []);
        }
    }
    function propagateToListener(promise, listener) {
        if (promise._state === null) {
            promise._listeners.push(listener);
            return;
        }
        var cb = promise._state ? listener.onFulfilled : listener.onRejected;
        if (cb === null) {
            return (promise._state ? listener.resolve : listener.reject)(promise._value);
        }
        ++listener.psd.ref;
        ++numScheduledCalls;
        asap(callListener, [cb, promise, listener]);
    }
    function callListener(cb, promise, listener) {
        try {
            var ret, value = promise._value;
            if (!promise._state && rejectingErrors.length)
                rejectingErrors = [];
            ret = debug && promise._consoleTask ? promise._consoleTask.run(function () { return cb(value); }) : cb(value);
            if (!promise._state && rejectingErrors.indexOf(value) === -1) {
                markErrorAsHandled(promise);
            }
            listener.resolve(ret);
        }
        catch (e) {
            listener.reject(e);
        }
        finally {
            if (--numScheduledCalls === 0)
                finalizePhysicalTick();
            --listener.psd.ref || listener.psd.finalize();
        }
    }
    function physicalTick() {
        usePSD(globalPSD, function () {
            beginMicroTickScope() && endMicroTickScope();
        });
    }
    function beginMicroTickScope() {
        var wasRootExec = isOutsideMicroTick;
        isOutsideMicroTick = false;
        needsNewPhysicalTick = false;
        return wasRootExec;
    }
    function endMicroTickScope() {
        var callbacks, i, l;
        do {
            while (microtickQueue.length > 0) {
                callbacks = microtickQueue;
                microtickQueue = [];
                l = callbacks.length;
                for (i = 0; i < l; ++i) {
                    var item = callbacks[i];
                    item[0].apply(null, item[1]);
                }
            }
        } while (microtickQueue.length > 0);
        isOutsideMicroTick = true;
        needsNewPhysicalTick = true;
    }
    function finalizePhysicalTick() {
        var unhandledErrs = unhandledErrors;
        unhandledErrors = [];
        unhandledErrs.forEach(function (p) {
            p._PSD.onunhandled.call(null, p._value, p);
        });
        var finalizers = tickFinalizers.slice(0);
        var i = finalizers.length;
        while (i)
            finalizers[--i]();
    }
    function run_at_end_of_this_or_next_physical_tick(fn) {
        function finalizer() {
            fn();
            tickFinalizers.splice(tickFinalizers.indexOf(finalizer), 1);
        }
        tickFinalizers.push(finalizer);
        ++numScheduledCalls;
        asap(function () {
            if (--numScheduledCalls === 0)
                finalizePhysicalTick();
        }, []);
    }
    function addPossiblyUnhandledError(promise) {
        if (!unhandledErrors.some(function (p) { return p._value === promise._value; }))
            unhandledErrors.push(promise);
    }
    function markErrorAsHandled(promise) {
        var i = unhandledErrors.length;
        while (i)
            if (unhandledErrors[--i]._value === promise._value) {
                unhandledErrors.splice(i, 1);
                return;
            }
    }
    function PromiseReject(reason) {
        return new DexiePromise(INTERNAL, false, reason);
    }
    function wrap(fn, errorCatcher) {
        var psd = PSD;
        return function () {
            var wasRootExec = beginMicroTickScope(), outerScope = PSD;
            try {
                switchToZone(psd, true);
                return fn.apply(this, arguments);
            }
            catch (e) {
                errorCatcher && errorCatcher(e);
            }
            finally {
                switchToZone(outerScope, false);
                if (wasRootExec)
                    endMicroTickScope();
            }
        };
    }
    var task = { awaits: 0, echoes: 0, id: 0 };
    var taskCounter = 0;
    var zoneStack = [];
    var zoneEchoes = 0;
    var totalEchoes = 0;
    var zone_id_counter = 0;
    function newScope(fn, props, a1, a2) {
        var parent = PSD, psd = Object.create(parent);
        psd.parent = parent;
        psd.ref = 0;
        psd.global = false;
        psd.id = ++zone_id_counter;
        globalPSD.env;
        psd.env = patchGlobalPromise ? {
            Promise: DexiePromise,
            PromiseProp: { value: DexiePromise, configurable: true, writable: true },
            all: DexiePromise.all,
            race: DexiePromise.race,
            allSettled: DexiePromise.allSettled,
            any: DexiePromise.any,
            resolve: DexiePromise.resolve,
            reject: DexiePromise.reject,
        } : {};
        if (props)
            extend(psd, props);
        ++parent.ref;
        psd.finalize = function () {
            --this.parent.ref || this.parent.finalize();
        };
        var rv = usePSD(psd, fn, a1, a2);
        if (psd.ref === 0)
            psd.finalize();
        return rv;
    }
    function incrementExpectedAwaits() {
        if (!task.id)
            task.id = ++taskCounter;
        ++task.awaits;
        task.echoes += ZONE_ECHO_LIMIT;
        return task.id;
    }
    function decrementExpectedAwaits() {
        if (!task.awaits)
            return false;
        if (--task.awaits === 0)
            task.id = 0;
        task.echoes = task.awaits * ZONE_ECHO_LIMIT;
        return true;
    }
    if (('' + nativePromiseThen).indexOf('[native code]') === -1) {
        incrementExpectedAwaits = decrementExpectedAwaits = nop;
    }
    function onPossibleParallellAsync(possiblePromise) {
        if (task.echoes && possiblePromise && possiblePromise.constructor === NativePromise) {
            incrementExpectedAwaits();
            return possiblePromise.then(function (x) {
                decrementExpectedAwaits();
                return x;
            }, function (e) {
                decrementExpectedAwaits();
                return rejection(e);
            });
        }
        return possiblePromise;
    }
    function zoneEnterEcho(targetZone) {
        ++totalEchoes;
        if (!task.echoes || --task.echoes === 0) {
            task.echoes = task.awaits = task.id = 0;
        }
        zoneStack.push(PSD);
        switchToZone(targetZone, true);
    }
    function zoneLeaveEcho() {
        var zone = zoneStack[zoneStack.length - 1];
        zoneStack.pop();
        switchToZone(zone, false);
    }
    function switchToZone(targetZone, bEnteringZone) {
        var currentZone = PSD;
        if (bEnteringZone ? task.echoes && (!zoneEchoes++ || targetZone !== PSD) : zoneEchoes && (!--zoneEchoes || targetZone !== PSD)) {
            queueMicrotask(bEnteringZone ? zoneEnterEcho.bind(null, targetZone) : zoneLeaveEcho);
        }
        if (targetZone === PSD)
            return;
        PSD = targetZone;
        if (currentZone === globalPSD)
            globalPSD.env = snapShot();
        if (patchGlobalPromise) {
            var GlobalPromise = globalPSD.env.Promise;
            var targetEnv = targetZone.env;
            if (currentZone.global || targetZone.global) {
                Object.defineProperty(_global, 'Promise', targetEnv.PromiseProp);
                GlobalPromise.all = targetEnv.all;
                GlobalPromise.race = targetEnv.race;
                GlobalPromise.resolve = targetEnv.resolve;
                GlobalPromise.reject = targetEnv.reject;
                if (targetEnv.allSettled)
                    GlobalPromise.allSettled = targetEnv.allSettled;
                if (targetEnv.any)
                    GlobalPromise.any = targetEnv.any;
            }
        }
    }
    function snapShot() {
        var GlobalPromise = _global.Promise;
        return patchGlobalPromise ? {
            Promise: GlobalPromise,
            PromiseProp: Object.getOwnPropertyDescriptor(_global, "Promise"),
            all: GlobalPromise.all,
            race: GlobalPromise.race,
            allSettled: GlobalPromise.allSettled,
            any: GlobalPromise.any,
            resolve: GlobalPromise.resolve,
            reject: GlobalPromise.reject,
        } : {};
    }
    function usePSD(psd, fn, a1, a2, a3) {
        var outerScope = PSD;
        try {
            switchToZone(psd, true);
            return fn(a1, a2, a3);
        }
        finally {
            switchToZone(outerScope, false);
        }
    }
    function nativeAwaitCompatibleWrap(fn, zone, possibleAwait, cleanup) {
        return typeof fn !== 'function' ? fn : function () {
            var outerZone = PSD;
            if (possibleAwait)
                incrementExpectedAwaits();
            switchToZone(zone, true);
            try {
                return fn.apply(this, arguments);
            }
            finally {
                switchToZone(outerZone, false);
                if (cleanup)
                    queueMicrotask(decrementExpectedAwaits);
            }
        };
    }
    function execInGlobalContext(cb) {
        if (Promise === NativePromise && task.echoes === 0) {
            if (zoneEchoes === 0) {
                cb();
            }
            else {
                enqueueNativeMicroTask(cb);
            }
        }
        else {
            setTimeout(cb, 0);
        }
    }
    var rejection = DexiePromise.reject;

    function tempTransaction(db, mode, storeNames, fn) {
        if (!db.idbdb || (!db._state.openComplete && (!PSD.letThrough && !db._vip))) {
            if (db._state.openComplete) {
                return rejection(new exceptions.DatabaseClosed(db._state.dbOpenError));
            }
            if (!db._state.isBeingOpened) {
                if (!db._state.autoOpen)
                    return rejection(new exceptions.DatabaseClosed());
                db.open().catch(nop);
            }
            return db._state.dbReadyPromise.then(function () { return tempTransaction(db, mode, storeNames, fn); });
        }
        else {
            var trans = db._createTransaction(mode, storeNames, db._dbSchema);
            try {
                trans.create();
                db._state.PR1398_maxLoop = 3;
            }
            catch (ex) {
                if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) {
                    console.warn('Dexie: Need to reopen db');
                    db.close({ disableAutoOpen: false });
                    return db.open().then(function () { return tempTransaction(db, mode, storeNames, fn); });
                }
                return rejection(ex);
            }
            return trans._promise(mode, function (resolve, reject) {
                return newScope(function () {
                    PSD.trans = trans;
                    return fn(resolve, reject, trans);
                });
            }).then(function (result) {
                if (mode === 'readwrite')
                    try {
                        trans.idbtrans.commit();
                    }
                    catch (_a) { }
                return mode === 'readonly' ? result : trans._completion.then(function () { return result; });
            });
        }
    }

    var DEXIE_VERSION = '4.0.11';
    var maxString = String.fromCharCode(65535);
    var minKey = -Infinity;
    var INVALID_KEY_ARGUMENT = "Invalid key provided. Keys must be of type string, number, Date or Array<string | number | Date>.";
    var STRING_EXPECTED = "String expected.";
    var connections = [];
    var DBNAMES_DB = '__dbnames';
    var READONLY = 'readonly';
    var READWRITE = 'readwrite';

    function combine(filter1, filter2) {
        return filter1 ?
            filter2 ?
                function () { return filter1.apply(this, arguments) && filter2.apply(this, arguments); } :
                filter1 :
            filter2;
    }

    var AnyRange = {
        type: 3 ,
        lower: -Infinity,
        lowerOpen: false,
        upper: [[]],
        upperOpen: false
    };

    function workaroundForUndefinedPrimKey(keyPath) {
        return typeof keyPath === "string" && !/\./.test(keyPath)
            ? function (obj) {
                if (obj[keyPath] === undefined && (keyPath in obj)) {
                    obj = deepClone(obj);
                    delete obj[keyPath];
                }
                return obj;
            }
            : function (obj) { return obj; };
    }

    function Entity() {
        throw exceptions.Type();
    }

    function cmp(a, b) {
        try {
            var ta = type(a);
            var tb = type(b);
            if (ta !== tb) {
                if (ta === 'Array')
                    return 1;
                if (tb === 'Array')
                    return -1;
                if (ta === 'binary')
                    return 1;
                if (tb === 'binary')
                    return -1;
                if (ta === 'string')
                    return 1;
                if (tb === 'string')
                    return -1;
                if (ta === 'Date')
                    return 1;
                if (tb !== 'Date')
                    return NaN;
                return -1;
            }
            switch (ta) {
                case 'number':
                case 'Date':
                case 'string':
                    return a > b ? 1 : a < b ? -1 : 0;
                case 'binary': {
                    return compareUint8Arrays(getUint8Array(a), getUint8Array(b));
                }
                case 'Array':
                    return compareArrays(a, b);
            }
        }
        catch (_a) { }
        return NaN;
    }
    function compareArrays(a, b) {
        var al = a.length;
        var bl = b.length;
        var l = al < bl ? al : bl;
        for (var i = 0; i < l; ++i) {
            var res = cmp(a[i], b[i]);
            if (res !== 0)
                return res;
        }
        return al === bl ? 0 : al < bl ? -1 : 1;
    }
    function compareUint8Arrays(a, b) {
        var al = a.length;
        var bl = b.length;
        var l = al < bl ? al : bl;
        for (var i = 0; i < l; ++i) {
            if (a[i] !== b[i])
                return a[i] < b[i] ? -1 : 1;
        }
        return al === bl ? 0 : al < bl ? -1 : 1;
    }
    function type(x) {
        var t = typeof x;
        if (t !== 'object')
            return t;
        if (ArrayBuffer.isView(x))
            return 'binary';
        var tsTag = toStringTag(x);
        return tsTag === 'ArrayBuffer' ? 'binary' : tsTag;
    }
    function getUint8Array(a) {
        if (a instanceof Uint8Array)
            return a;
        if (ArrayBuffer.isView(a))
            return new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
        return new Uint8Array(a);
    }

    var Table =  (function () {
        function Table() {
        }
        Table.prototype._trans = function (mode, fn, writeLocked) {
            var trans = this._tx || PSD.trans;
            var tableName = this.name;
            var task = debug && typeof console !== 'undefined' && console.createTask && console.createTask("Dexie: ".concat(mode === 'readonly' ? 'read' : 'write', " ").concat(this.name));
            function checkTableInTransaction(resolve, reject, trans) {
                if (!trans.schema[tableName])
                    throw new exceptions.NotFound("Table " + tableName + " not part of transaction");
                return fn(trans.idbtrans, trans);
            }
            var wasRootExec = beginMicroTickScope();
            try {
                var p = trans && trans.db._novip === this.db._novip ?
                    trans === PSD.trans ?
                        trans._promise(mode, checkTableInTransaction, writeLocked) :
                        newScope(function () { return trans._promise(mode, checkTableInTransaction, writeLocked); }, { trans: trans, transless: PSD.transless || PSD }) :
                    tempTransaction(this.db, mode, [this.name], checkTableInTransaction);
                if (task) {
                    p._consoleTask = task;
                    p = p.catch(function (err) {
                        console.trace(err);
                        return rejection(err);
                    });
                }
                return p;
            }
            finally {
                if (wasRootExec)
                    endMicroTickScope();
            }
        };
        Table.prototype.get = function (keyOrCrit, cb) {
            var _this = this;
            if (keyOrCrit && keyOrCrit.constructor === Object)
                return this.where(keyOrCrit).first(cb);
            if (keyOrCrit == null)
                return rejection(new exceptions.Type("Invalid argument to Table.get()"));
            return this._trans('readonly', function (trans) {
                return _this.core.get({ trans: trans, key: keyOrCrit })
                    .then(function (res) { return _this.hook.reading.fire(res); });
            }).then(cb);
        };
        Table.prototype.where = function (indexOrCrit) {
            if (typeof indexOrCrit === 'string')
                return new this.db.WhereClause(this, indexOrCrit);
            if (isArray(indexOrCrit))
                return new this.db.WhereClause(this, "[".concat(indexOrCrit.join('+'), "]"));
            var keyPaths = keys(indexOrCrit);
            if (keyPaths.length === 1)
                return this
                    .where(keyPaths[0])
                    .equals(indexOrCrit[keyPaths[0]]);
            var compoundIndex = this.schema.indexes.concat(this.schema.primKey).filter(function (ix) {
                if (ix.compound &&
                    keyPaths.every(function (keyPath) { return ix.keyPath.indexOf(keyPath) >= 0; })) {
                    for (var i = 0; i < keyPaths.length; ++i) {
                        if (keyPaths.indexOf(ix.keyPath[i]) === -1)
                            return false;
                    }
                    return true;
                }
                return false;
            }).sort(function (a, b) { return a.keyPath.length - b.keyPath.length; })[0];
            if (compoundIndex && this.db._maxKey !== maxString) {
                var keyPathsInValidOrder = compoundIndex.keyPath.slice(0, keyPaths.length);
                return this
                    .where(keyPathsInValidOrder)
                    .equals(keyPathsInValidOrder.map(function (kp) { return indexOrCrit[kp]; }));
            }
            if (!compoundIndex && debug)
                console.warn("The query ".concat(JSON.stringify(indexOrCrit), " on ").concat(this.name, " would benefit from a ") +
                    "compound index [".concat(keyPaths.join('+'), "]"));
            var idxByName = this.schema.idxByName;
            function equals(a, b) {
                return cmp(a, b) === 0;
            }
            var _a = keyPaths.reduce(function (_a, keyPath) {
                var prevIndex = _a[0], prevFilterFn = _a[1];
                var index = idxByName[keyPath];
                var value = indexOrCrit[keyPath];
                return [
                    prevIndex || index,
                    prevIndex || !index ?
                        combine(prevFilterFn, index && index.multi ?
                            function (x) {
                                var prop = getByKeyPath(x, keyPath);
                                return isArray(prop) && prop.some(function (item) { return equals(value, item); });
                            } : function (x) { return equals(value, getByKeyPath(x, keyPath)); })
                        : prevFilterFn
                ];
            }, [null, null]), idx = _a[0], filterFunction = _a[1];
            return idx ?
                this.where(idx.name).equals(indexOrCrit[idx.keyPath])
                    .filter(filterFunction) :
                compoundIndex ?
                    this.filter(filterFunction) :
                    this.where(keyPaths).equals('');
        };
        Table.prototype.filter = function (filterFunction) {
            return this.toCollection().and(filterFunction);
        };
        Table.prototype.count = function (thenShortcut) {
            return this.toCollection().count(thenShortcut);
        };
        Table.prototype.offset = function (offset) {
            return this.toCollection().offset(offset);
        };
        Table.prototype.limit = function (numRows) {
            return this.toCollection().limit(numRows);
        };
        Table.prototype.each = function (callback) {
            return this.toCollection().each(callback);
        };
        Table.prototype.toArray = function (thenShortcut) {
            return this.toCollection().toArray(thenShortcut);
        };
        Table.prototype.toCollection = function () {
            return new this.db.Collection(new this.db.WhereClause(this));
        };
        Table.prototype.orderBy = function (index) {
            return new this.db.Collection(new this.db.WhereClause(this, isArray(index) ?
                "[".concat(index.join('+'), "]") :
                index));
        };
        Table.prototype.reverse = function () {
            return this.toCollection().reverse();
        };
        Table.prototype.mapToClass = function (constructor) {
            var _a = this, db = _a.db, tableName = _a.name;
            this.schema.mappedClass = constructor;
            if (constructor.prototype instanceof Entity) {
                constructor =  (function (_super) {
                    __extends(class_1, _super);
                    function class_1() {
                        return _super !== null && _super.apply(this, arguments) || this;
                    }
                    Object.defineProperty(class_1.prototype, "db", {
                        get: function () { return db; },
                        enumerable: false,
                        configurable: true
                    });
                    class_1.prototype.table = function () { return tableName; };
                    return class_1;
                }(constructor));
            }
            var inheritedProps = new Set();
            for (var proto = constructor.prototype; proto; proto = getProto(proto)) {
                Object.getOwnPropertyNames(proto).forEach(function (propName) { return inheritedProps.add(propName); });
            }
            var readHook = function (obj) {
                if (!obj)
                    return obj;
                var res = Object.create(constructor.prototype);
                for (var m in obj)
                    if (!inheritedProps.has(m))
                        try {
                            res[m] = obj[m];
                        }
                        catch (_) { }
                return res;
            };
            if (this.schema.readHook) {
                this.hook.reading.unsubscribe(this.schema.readHook);
            }
            this.schema.readHook = readHook;
            this.hook("reading", readHook);
            return constructor;
        };
        Table.prototype.defineClass = function () {
            function Class(content) {
                extend(this, content);
            }
            return this.mapToClass(Class);
        };
        Table.prototype.add = function (obj, key) {
            var _this = this;
            var _a = this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
            var objToAdd = obj;
            if (keyPath && auto) {
                objToAdd = workaroundForUndefinedPrimKey(keyPath)(obj);
            }
            return this._trans('readwrite', function (trans) {
                return _this.core.mutate({ trans: trans, type: 'add', keys: key != null ? [key] : null, values: [objToAdd] });
            }).then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : res.lastResult; })
                .then(function (lastResult) {
                if (keyPath) {
                    try {
                        setByKeyPath(obj, keyPath, lastResult);
                    }
                    catch (_) { }
                }
                return lastResult;
            });
        };
        Table.prototype.update = function (keyOrObject, modifications) {
            if (typeof keyOrObject === 'object' && !isArray(keyOrObject)) {
                var key = getByKeyPath(keyOrObject, this.schema.primKey.keyPath);
                if (key === undefined)
                    return rejection(new exceptions.InvalidArgument("Given object does not contain its primary key"));
                return this.where(":id").equals(key).modify(modifications);
            }
            else {
                return this.where(":id").equals(keyOrObject).modify(modifications);
            }
        };
        Table.prototype.put = function (obj, key) {
            var _this = this;
            var _a = this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
            var objToAdd = obj;
            if (keyPath && auto) {
                objToAdd = workaroundForUndefinedPrimKey(keyPath)(obj);
            }
            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'put', values: [objToAdd], keys: key != null ? [key] : null }); })
                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : res.lastResult; })
                .then(function (lastResult) {
                if (keyPath) {
                    try {
                        setByKeyPath(obj, keyPath, lastResult);
                    }
                    catch (_) { }
                }
                return lastResult;
            });
        };
        Table.prototype.delete = function (key) {
            var _this = this;
            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'delete', keys: [key] }); })
                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
        };
        Table.prototype.clear = function () {
            var _this = this;
            return this._trans('readwrite', function (trans) { return _this.core.mutate({ trans: trans, type: 'deleteRange', range: AnyRange }); })
                .then(function (res) { return res.numFailures ? DexiePromise.reject(res.failures[0]) : undefined; });
        };
        Table.prototype.bulkGet = function (keys) {
            var _this = this;
            return this._trans('readonly', function (trans) {
                return _this.core.getMany({
                    keys: keys,
                    trans: trans
                }).then(function (result) { return result.map(function (res) { return _this.hook.reading.fire(res); }); });
            });
        };
        Table.prototype.bulkAdd = function (objects, keysOrOptions, options) {
            var _this = this;
            var keys = Array.isArray(keysOrOptions) ? keysOrOptions : undefined;
            options = options || (keys ? undefined : keysOrOptions);
            var wantResults = options ? options.allKeys : undefined;
            return this._trans('readwrite', function (trans) {
                var _a = _this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
                if (keyPath && keys)
                    throw new exceptions.InvalidArgument("bulkAdd(): keys argument invalid on tables with inbound keys");
                if (keys && keys.length !== objects.length)
                    throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
                var numObjects = objects.length;
                var objectsToAdd = keyPath && auto ?
                    objects.map(workaroundForUndefinedPrimKey(keyPath)) :
                    objects;
                return _this.core.mutate({ trans: trans, type: 'add', keys: keys, values: objectsToAdd, wantResults: wantResults })
                    .then(function (_a) {
                    var numFailures = _a.numFailures, results = _a.results, lastResult = _a.lastResult, failures = _a.failures;
                    var result = wantResults ? results : lastResult;
                    if (numFailures === 0)
                        return result;
                    throw new BulkError("".concat(_this.name, ".bulkAdd(): ").concat(numFailures, " of ").concat(numObjects, " operations failed"), failures);
                });
            });
        };
        Table.prototype.bulkPut = function (objects, keysOrOptions, options) {
            var _this = this;
            var keys = Array.isArray(keysOrOptions) ? keysOrOptions : undefined;
            options = options || (keys ? undefined : keysOrOptions);
            var wantResults = options ? options.allKeys : undefined;
            return this._trans('readwrite', function (trans) {
                var _a = _this.schema.primKey, auto = _a.auto, keyPath = _a.keyPath;
                if (keyPath && keys)
                    throw new exceptions.InvalidArgument("bulkPut(): keys argument invalid on tables with inbound keys");
                if (keys && keys.length !== objects.length)
                    throw new exceptions.InvalidArgument("Arguments objects and keys must have the same length");
                var numObjects = objects.length;
                var objectsToPut = keyPath && auto ?
                    objects.map(workaroundForUndefinedPrimKey(keyPath)) :
                    objects;
                return _this.core.mutate({ trans: trans, type: 'put', keys: keys, values: objectsToPut, wantResults: wantResults })
                    .then(function (_a) {
                    var numFailures = _a.numFailures, results = _a.results, lastResult = _a.lastResult, failures = _a.failures;
                    var result = wantResults ? results : lastResult;
                    if (numFailures === 0)
                        return result;
                    throw new BulkError("".concat(_this.name, ".bulkPut(): ").concat(numFailures, " of ").concat(numObjects, " operations failed"), failures);
                });
            });
        };
        Table.prototype.bulkUpdate = function (keysAndChanges) {
            var _this = this;
            var coreTable = this.core;
            var keys = keysAndChanges.map(function (entry) { return entry.key; });
            var changeSpecs = keysAndChanges.map(function (entry) { return entry.changes; });
            var offsetMap = [];
            return this._trans('readwrite', function (trans) {
                return coreTable.getMany({ trans: trans, keys: keys, cache: 'clone' }).then(function (objs) {
                    var resultKeys = [];
                    var resultObjs = [];
                    keysAndChanges.forEach(function (_a, idx) {
                        var key = _a.key, changes = _a.changes;
                        var obj = objs[idx];
                        if (obj) {
                            for (var _i = 0, _b = Object.keys(changes); _i < _b.length; _i++) {
                                var keyPath = _b[_i];
                                var value = changes[keyPath];
                                if (keyPath === _this.schema.primKey.keyPath) {
                                    if (cmp(value, key) !== 0) {
                                        throw new exceptions.Constraint("Cannot update primary key in bulkUpdate()");
                                    }
                                }
                                else {
                                    setByKeyPath(obj, keyPath, value);
                                }
                            }
                            offsetMap.push(idx);
                            resultKeys.push(key);
                            resultObjs.push(obj);
                        }
                    });
                    var numEntries = resultKeys.length;
                    return coreTable
                        .mutate({
                        trans: trans,
                        type: 'put',
                        keys: resultKeys,
                        values: resultObjs,
                        updates: {
                            keys: keys,
                            changeSpecs: changeSpecs
                        }
                    })
                        .then(function (_a) {
                        var numFailures = _a.numFailures, failures = _a.failures;
                        if (numFailures === 0)
                            return numEntries;
                        for (var _i = 0, _b = Object.keys(failures); _i < _b.length; _i++) {
                            var offset = _b[_i];
                            var mappedOffset = offsetMap[Number(offset)];
                            if (mappedOffset != null) {
                                var failure = failures[offset];
                                delete failures[offset];
                                failures[mappedOffset] = failure;
                            }
                        }
                        throw new BulkError("".concat(_this.name, ".bulkUpdate(): ").concat(numFailures, " of ").concat(numEntries, " operations failed"), failures);
                    });
                });
            });
        };
        Table.prototype.bulkDelete = function (keys) {
            var _this = this;
            var numKeys = keys.length;
            return this._trans('readwrite', function (trans) {
                return _this.core.mutate({ trans: trans, type: 'delete', keys: keys });
            }).then(function (_a) {
                var numFailures = _a.numFailures, lastResult = _a.lastResult, failures = _a.failures;
                if (numFailures === 0)
                    return lastResult;
                throw new BulkError("".concat(_this.name, ".bulkDelete(): ").concat(numFailures, " of ").concat(numKeys, " operations failed"), failures);
            });
        };
        return Table;
    }());

    function Events(ctx) {
        var evs = {};
        var rv = function (eventName, subscriber) {
            if (subscriber) {
                var i = arguments.length, args = new Array(i - 1);
                while (--i)
                    args[i - 1] = arguments[i];
                evs[eventName].subscribe.apply(null, args);
                return ctx;
            }
            else if (typeof (eventName) === 'string') {
                return evs[eventName];
            }
        };
        rv.addEventType = add;
        for (var i = 1, l = arguments.length; i < l; ++i) {
            add(arguments[i]);
        }
        return rv;
        function add(eventName, chainFunction, defaultFunction) {
            if (typeof eventName === 'object')
                return addConfiguredEvents(eventName);
            if (!chainFunction)
                chainFunction = reverseStoppableEventChain;
            if (!defaultFunction)
                defaultFunction = nop;
            var context = {
                subscribers: [],
                fire: defaultFunction,
                subscribe: function (cb) {
                    if (context.subscribers.indexOf(cb) === -1) {
                        context.subscribers.push(cb);
                        context.fire = chainFunction(context.fire, cb);
                    }
                },
                unsubscribe: function (cb) {
                    context.subscribers = context.subscribers.filter(function (fn) { return fn !== cb; });
                    context.fire = context.subscribers.reduce(chainFunction, defaultFunction);
                }
            };
            evs[eventName] = rv[eventName] = context;
            return context;
        }
        function addConfiguredEvents(cfg) {
            keys(cfg).forEach(function (eventName) {
                var args = cfg[eventName];
                if (isArray(args)) {
                    add(eventName, cfg[eventName][0], cfg[eventName][1]);
                }
                else if (args === 'asap') {
                    var context = add(eventName, mirror, function fire() {
                        var i = arguments.length, args = new Array(i);
                        while (i--)
                            args[i] = arguments[i];
                        context.subscribers.forEach(function (fn) {
                            asap$1(function fireEvent() {
                                fn.apply(null, args);
                            });
                        });
                    });
                }
                else
                    throw new exceptions.InvalidArgument("Invalid event config");
            });
        }
    }

    function makeClassConstructor(prototype, constructor) {
        derive(constructor).from({ prototype: prototype });
        return constructor;
    }

    function createTableConstructor(db) {
        return makeClassConstructor(Table.prototype, function Table(name, tableSchema, trans) {
            this.db = db;
            this._tx = trans;
            this.name = name;
            this.schema = tableSchema;
            this.hook = db._allTables[name] ? db._allTables[name].hook : Events(null, {
                "creating": [hookCreatingChain, nop],
                "reading": [pureFunctionChain, mirror],
                "updating": [hookUpdatingChain, nop],
                "deleting": [hookDeletingChain, nop]
            });
        });
    }

    function isPlainKeyRange(ctx, ignoreLimitFilter) {
        return !(ctx.filter || ctx.algorithm || ctx.or) &&
            (ignoreLimitFilter ? ctx.justLimit : !ctx.replayFilter);
    }
    function addFilter(ctx, fn) {
        ctx.filter = combine(ctx.filter, fn);
    }
    function addReplayFilter(ctx, factory, isLimitFilter) {
        var curr = ctx.replayFilter;
        ctx.replayFilter = curr ? function () { return combine(curr(), factory()); } : factory;
        ctx.justLimit = isLimitFilter && !curr;
    }
    function addMatchFilter(ctx, fn) {
        ctx.isMatch = combine(ctx.isMatch, fn);
    }
    function getIndexOrStore(ctx, coreSchema) {
        if (ctx.isPrimKey)
            return coreSchema.primaryKey;
        var index = coreSchema.getIndexByKeyPath(ctx.index);
        if (!index)
            throw new exceptions.Schema("KeyPath " + ctx.index + " on object store " + coreSchema.name + " is not indexed");
        return index;
    }
    function openCursor(ctx, coreTable, trans) {
        var index = getIndexOrStore(ctx, coreTable.schema);
        return coreTable.openCursor({
            trans: trans,
            values: !ctx.keysOnly,
            reverse: ctx.dir === 'prev',
            unique: !!ctx.unique,
            query: {
                index: index,
                range: ctx.range
            }
        });
    }
    function iter(ctx, fn, coreTrans, coreTable) {
        var filter = ctx.replayFilter ? combine(ctx.filter, ctx.replayFilter()) : ctx.filter;
        if (!ctx.or) {
            return iterate(openCursor(ctx, coreTable, coreTrans), combine(ctx.algorithm, filter), fn, !ctx.keysOnly && ctx.valueMapper);
        }
        else {
            var set_1 = {};
            var union = function (item, cursor, advance) {
                if (!filter || filter(cursor, advance, function (result) { return cursor.stop(result); }, function (err) { return cursor.fail(err); })) {
                    var primaryKey = cursor.primaryKey;
                    var key = '' + primaryKey;
                    if (key === '[object ArrayBuffer]')
                        key = '' + new Uint8Array(primaryKey);
                    if (!hasOwn(set_1, key)) {
                        set_1[key] = true;
                        fn(item, cursor, advance);
                    }
                }
            };
            return Promise.all([
                ctx.or._iterate(union, coreTrans),
                iterate(openCursor(ctx, coreTable, coreTrans), ctx.algorithm, union, !ctx.keysOnly && ctx.valueMapper)
            ]);
        }
    }
    function iterate(cursorPromise, filter, fn, valueMapper) {
        var mappedFn = valueMapper ? function (x, c, a) { return fn(valueMapper(x), c, a); } : fn;
        var wrappedFn = wrap(mappedFn);
        return cursorPromise.then(function (cursor) {
            if (cursor) {
                return cursor.start(function () {
                    var c = function () { return cursor.continue(); };
                    if (!filter || filter(cursor, function (advancer) { return c = advancer; }, function (val) { cursor.stop(val); c = nop; }, function (e) { cursor.fail(e); c = nop; }))
                        wrappedFn(cursor.value, cursor, function (advancer) { return c = advancer; });
                    c();
                });
            }
        });
    }

    var PropModification =  (function () {
        function PropModification(spec) {
            this["@@propmod"] = spec;
        }
        PropModification.prototype.execute = function (value) {
            var _a;
            var spec = this["@@propmod"];
            if (spec.add !== undefined) {
                var term = spec.add;
                if (isArray(term)) {
                    return __spreadArray(__spreadArray([], (isArray(value) ? value : []), true), term, true).sort();
                }
                if (typeof term === 'number')
                    return (Number(value) || 0) + term;
                if (typeof term === 'bigint') {
                    try {
                        return BigInt(value) + term;
                    }
                    catch (_b) {
                        return BigInt(0) + term;
                    }
                }
                throw new TypeError("Invalid term ".concat(term));
            }
            if (spec.remove !== undefined) {
                var subtrahend_1 = spec.remove;
                if (isArray(subtrahend_1)) {
                    return isArray(value) ? value.filter(function (item) { return !subtrahend_1.includes(item); }).sort() : [];
                }
                if (typeof subtrahend_1 === 'number')
                    return Number(value) - subtrahend_1;
                if (typeof subtrahend_1 === 'bigint') {
                    try {
                        return BigInt(value) - subtrahend_1;
                    }
                    catch (_c) {
                        return BigInt(0) - subtrahend_1;
                    }
                }
                throw new TypeError("Invalid subtrahend ".concat(subtrahend_1));
            }
            var prefixToReplace = (_a = spec.replacePrefix) === null || _a === void 0 ? void 0 : _a[0];
            if (prefixToReplace && typeof value === 'string' && value.startsWith(prefixToReplace)) {
                return spec.replacePrefix[1] + value.substring(prefixToReplace.length);
            }
            return value;
        };
        return PropModification;
    }());

    var Collection =  (function () {
        function Collection() {
        }
        Collection.prototype._read = function (fn, cb) {
            var ctx = this._ctx;
            return ctx.error ?
                ctx.table._trans(null, rejection.bind(null, ctx.error)) :
                ctx.table._trans('readonly', fn).then(cb);
        };
        Collection.prototype._write = function (fn) {
            var ctx = this._ctx;
            return ctx.error ?
                ctx.table._trans(null, rejection.bind(null, ctx.error)) :
                ctx.table._trans('readwrite', fn, "locked");
        };
        Collection.prototype._addAlgorithm = function (fn) {
            var ctx = this._ctx;
            ctx.algorithm = combine(ctx.algorithm, fn);
        };
        Collection.prototype._iterate = function (fn, coreTrans) {
            return iter(this._ctx, fn, coreTrans, this._ctx.table.core);
        };
        Collection.prototype.clone = function (props) {
            var rv = Object.create(this.constructor.prototype), ctx = Object.create(this._ctx);
            if (props)
                extend(ctx, props);
            rv._ctx = ctx;
            return rv;
        };
        Collection.prototype.raw = function () {
            this._ctx.valueMapper = null;
            return this;
        };
        Collection.prototype.each = function (fn) {
            var ctx = this._ctx;
            return this._read(function (trans) { return iter(ctx, fn, trans, ctx.table.core); });
        };
        Collection.prototype.count = function (cb) {
            var _this = this;
            return this._read(function (trans) {
                var ctx = _this._ctx;
                var coreTable = ctx.table.core;
                if (isPlainKeyRange(ctx, true)) {
                    return coreTable.count({
                        trans: trans,
                        query: {
                            index: getIndexOrStore(ctx, coreTable.schema),
                            range: ctx.range
                        }
                    }).then(function (count) { return Math.min(count, ctx.limit); });
                }
                else {
                    var count = 0;
                    return iter(ctx, function () { ++count; return false; }, trans, coreTable)
                        .then(function () { return count; });
                }
            }).then(cb);
        };
        Collection.prototype.sortBy = function (keyPath, cb) {
            var parts = keyPath.split('.').reverse(), lastPart = parts[0], lastIndex = parts.length - 1;
            function getval(obj, i) {
                if (i)
                    return getval(obj[parts[i]], i - 1);
                return obj[lastPart];
            }
            var order = this._ctx.dir === "next" ? 1 : -1;
            function sorter(a, b) {
                var aVal = getval(a, lastIndex), bVal = getval(b, lastIndex);
                return cmp(aVal, bVal) * order;
            }
            return this.toArray(function (a) {
                return a.sort(sorter);
            }).then(cb);
        };
        Collection.prototype.toArray = function (cb) {
            var _this = this;
            return this._read(function (trans) {
                var ctx = _this._ctx;
                if (ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
                    var valueMapper_1 = ctx.valueMapper;
                    var index = getIndexOrStore(ctx, ctx.table.core.schema);
                    return ctx.table.core.query({
                        trans: trans,
                        limit: ctx.limit,
                        values: true,
                        query: {
                            index: index,
                            range: ctx.range
                        }
                    }).then(function (_a) {
                        var result = _a.result;
                        return valueMapper_1 ? result.map(valueMapper_1) : result;
                    });
                }
                else {
                    var a_1 = [];
                    return iter(ctx, function (item) { return a_1.push(item); }, trans, ctx.table.core).then(function () { return a_1; });
                }
            }, cb);
        };
        Collection.prototype.offset = function (offset) {
            var ctx = this._ctx;
            if (offset <= 0)
                return this;
            ctx.offset += offset;
            if (isPlainKeyRange(ctx)) {
                addReplayFilter(ctx, function () {
                    var offsetLeft = offset;
                    return function (cursor, advance) {
                        if (offsetLeft === 0)
                            return true;
                        if (offsetLeft === 1) {
                            --offsetLeft;
                            return false;
                        }
                        advance(function () {
                            cursor.advance(offsetLeft);
                            offsetLeft = 0;
                        });
                        return false;
                    };
                });
            }
            else {
                addReplayFilter(ctx, function () {
                    var offsetLeft = offset;
                    return function () { return (--offsetLeft < 0); };
                });
            }
            return this;
        };
        Collection.prototype.limit = function (numRows) {
            this._ctx.limit = Math.min(this._ctx.limit, numRows);
            addReplayFilter(this._ctx, function () {
                var rowsLeft = numRows;
                return function (cursor, advance, resolve) {
                    if (--rowsLeft <= 0)
                        advance(resolve);
                    return rowsLeft >= 0;
                };
            }, true);
            return this;
        };
        Collection.prototype.until = function (filterFunction, bIncludeStopEntry) {
            addFilter(this._ctx, function (cursor, advance, resolve) {
                if (filterFunction(cursor.value)) {
                    advance(resolve);
                    return bIncludeStopEntry;
                }
                else {
                    return true;
                }
            });
            return this;
        };
        Collection.prototype.first = function (cb) {
            return this.limit(1).toArray(function (a) { return a[0]; }).then(cb);
        };
        Collection.prototype.last = function (cb) {
            return this.reverse().first(cb);
        };
        Collection.prototype.filter = function (filterFunction) {
            addFilter(this._ctx, function (cursor) {
                return filterFunction(cursor.value);
            });
            addMatchFilter(this._ctx, filterFunction);
            return this;
        };
        Collection.prototype.and = function (filter) {
            return this.filter(filter);
        };
        Collection.prototype.or = function (indexName) {
            return new this.db.WhereClause(this._ctx.table, indexName, this);
        };
        Collection.prototype.reverse = function () {
            this._ctx.dir = (this._ctx.dir === "prev" ? "next" : "prev");
            if (this._ondirectionchange)
                this._ondirectionchange(this._ctx.dir);
            return this;
        };
        Collection.prototype.desc = function () {
            return this.reverse();
        };
        Collection.prototype.eachKey = function (cb) {
            var ctx = this._ctx;
            ctx.keysOnly = !ctx.isMatch;
            return this.each(function (val, cursor) { cb(cursor.key, cursor); });
        };
        Collection.prototype.eachUniqueKey = function (cb) {
            this._ctx.unique = "unique";
            return this.eachKey(cb);
        };
        Collection.prototype.eachPrimaryKey = function (cb) {
            var ctx = this._ctx;
            ctx.keysOnly = !ctx.isMatch;
            return this.each(function (val, cursor) { cb(cursor.primaryKey, cursor); });
        };
        Collection.prototype.keys = function (cb) {
            var ctx = this._ctx;
            ctx.keysOnly = !ctx.isMatch;
            var a = [];
            return this.each(function (item, cursor) {
                a.push(cursor.key);
            }).then(function () {
                return a;
            }).then(cb);
        };
        Collection.prototype.primaryKeys = function (cb) {
            var ctx = this._ctx;
            if (ctx.dir === 'next' && isPlainKeyRange(ctx, true) && ctx.limit > 0) {
                return this._read(function (trans) {
                    var index = getIndexOrStore(ctx, ctx.table.core.schema);
                    return ctx.table.core.query({
                        trans: trans,
                        values: false,
                        limit: ctx.limit,
                        query: {
                            index: index,
                            range: ctx.range
                        }
                    });
                }).then(function (_a) {
                    var result = _a.result;
                    return result;
                }).then(cb);
            }
            ctx.keysOnly = !ctx.isMatch;
            var a = [];
            return this.each(function (item, cursor) {
                a.push(cursor.primaryKey);
            }).then(function () {
                return a;
            }).then(cb);
        };
        Collection.prototype.uniqueKeys = function (cb) {
            this._ctx.unique = "unique";
            return this.keys(cb);
        };
        Collection.prototype.firstKey = function (cb) {
            return this.limit(1).keys(function (a) { return a[0]; }).then(cb);
        };
        Collection.prototype.lastKey = function (cb) {
            return this.reverse().firstKey(cb);
        };
        Collection.prototype.distinct = function () {
            var ctx = this._ctx, idx = ctx.index && ctx.table.schema.idxByName[ctx.index];
            if (!idx || !idx.multi)
                return this;
            var set = {};
            addFilter(this._ctx, function (cursor) {
                var strKey = cursor.primaryKey.toString();
                var found = hasOwn(set, strKey);
                set[strKey] = true;
                return !found;
            });
            return this;
        };
        Collection.prototype.modify = function (changes) {
            var _this = this;
            var ctx = this._ctx;
            return this._write(function (trans) {
                var modifyer;
                if (typeof changes === 'function') {
                    modifyer = changes;
                }
                else {
                    var keyPaths = keys(changes);
                    var numKeys = keyPaths.length;
                    modifyer = function (item) {
                        var anythingModified = false;
                        for (var i = 0; i < numKeys; ++i) {
                            var keyPath = keyPaths[i];
                            var val = changes[keyPath];
                            var origVal = getByKeyPath(item, keyPath);
                            if (val instanceof PropModification) {
                                setByKeyPath(item, keyPath, val.execute(origVal));
                                anythingModified = true;
                            }
                            else if (origVal !== val) {
                                setByKeyPath(item, keyPath, val);
                                anythingModified = true;
                            }
                        }
                        return anythingModified;
                    };
                }
                var coreTable = ctx.table.core;
                var _a = coreTable.schema.primaryKey, outbound = _a.outbound, extractKey = _a.extractKey;
                var limit = 200;
                var modifyChunkSize = _this.db._options.modifyChunkSize;
                if (modifyChunkSize) {
                    if (typeof modifyChunkSize == 'object') {
                        limit = modifyChunkSize[coreTable.name] || modifyChunkSize['*'] || 200;
                    }
                    else {
                        limit = modifyChunkSize;
                    }
                }
                var totalFailures = [];
                var successCount = 0;
                var failedKeys = [];
                var applyMutateResult = function (expectedCount, res) {
                    var failures = res.failures, numFailures = res.numFailures;
                    successCount += expectedCount - numFailures;
                    for (var _i = 0, _a = keys(failures); _i < _a.length; _i++) {
                        var pos = _a[_i];
                        totalFailures.push(failures[pos]);
                    }
                };
                return _this.clone().primaryKeys().then(function (keys) {
                    var criteria = isPlainKeyRange(ctx) &&
                        ctx.limit === Infinity &&
                        (typeof changes !== 'function' || changes === deleteCallback) && {
                        index: ctx.index,
                        range: ctx.range
                    };
                    var nextChunk = function (offset) {
                        var count = Math.min(limit, keys.length - offset);
                        return coreTable.getMany({
                            trans: trans,
                            keys: keys.slice(offset, offset + count),
                            cache: "immutable"
                        }).then(function (values) {
                            var addValues = [];
                            var putValues = [];
                            var putKeys = outbound ? [] : null;
                            var deleteKeys = [];
                            for (var i = 0; i < count; ++i) {
                                var origValue = values[i];
                                var ctx_1 = {
                                    value: deepClone(origValue),
                                    primKey: keys[offset + i]
                                };
                                if (modifyer.call(ctx_1, ctx_1.value, ctx_1) !== false) {
                                    if (ctx_1.value == null) {
                                        deleteKeys.push(keys[offset + i]);
                                    }
                                    else if (!outbound && cmp(extractKey(origValue), extractKey(ctx_1.value)) !== 0) {
                                        deleteKeys.push(keys[offset + i]);
                                        addValues.push(ctx_1.value);
                                    }
                                    else {
                                        putValues.push(ctx_1.value);
                                        if (outbound)
                                            putKeys.push(keys[offset + i]);
                                    }
                                }
                            }
                            return Promise.resolve(addValues.length > 0 &&
                                coreTable.mutate({ trans: trans, type: 'add', values: addValues })
                                    .then(function (res) {
                                    for (var pos in res.failures) {
                                        deleteKeys.splice(parseInt(pos), 1);
                                    }
                                    applyMutateResult(addValues.length, res);
                                })).then(function () { return (putValues.length > 0 || (criteria && typeof changes === 'object')) &&
                                coreTable.mutate({
                                    trans: trans,
                                    type: 'put',
                                    keys: putKeys,
                                    values: putValues,
                                    criteria: criteria,
                                    changeSpec: typeof changes !== 'function'
                                        && changes,
                                    isAdditionalChunk: offset > 0
                                }).then(function (res) { return applyMutateResult(putValues.length, res); }); }).then(function () { return (deleteKeys.length > 0 || (criteria && changes === deleteCallback)) &&
                                coreTable.mutate({
                                    trans: trans,
                                    type: 'delete',
                                    keys: deleteKeys,
                                    criteria: criteria,
                                    isAdditionalChunk: offset > 0
                                }).then(function (res) { return applyMutateResult(deleteKeys.length, res); }); }).then(function () {
                                return keys.length > offset + count && nextChunk(offset + limit);
                            });
                        });
                    };
                    return nextChunk(0).then(function () {
                        if (totalFailures.length > 0)
                            throw new ModifyError("Error modifying one or more objects", totalFailures, successCount, failedKeys);
                        return keys.length;
                    });
                });
            });
        };
        Collection.prototype.delete = function () {
            var ctx = this._ctx, range = ctx.range;
            if (isPlainKeyRange(ctx) &&
                (ctx.isPrimKey || range.type === 3 ))
             {
                return this._write(function (trans) {
                    var primaryKey = ctx.table.core.schema.primaryKey;
                    var coreRange = range;
                    return ctx.table.core.count({ trans: trans, query: { index: primaryKey, range: coreRange } }).then(function (count) {
                        return ctx.table.core.mutate({ trans: trans, type: 'deleteRange', range: coreRange })
                            .then(function (_a) {
                            var failures = _a.failures; _a.lastResult; _a.results; var numFailures = _a.numFailures;
                            if (numFailures)
                                throw new ModifyError("Could not delete some values", Object.keys(failures).map(function (pos) { return failures[pos]; }), count - numFailures);
                            return count - numFailures;
                        });
                    });
                });
            }
            return this.modify(deleteCallback);
        };
        return Collection;
    }());
    var deleteCallback = function (value, ctx) { return ctx.value = null; };

    function createCollectionConstructor(db) {
        return makeClassConstructor(Collection.prototype, function Collection(whereClause, keyRangeGenerator) {
            this.db = db;
            var keyRange = AnyRange, error = null;
            if (keyRangeGenerator)
                try {
                    keyRange = keyRangeGenerator();
                }
                catch (ex) {
                    error = ex;
                }
            var whereCtx = whereClause._ctx;
            var table = whereCtx.table;
            var readingHook = table.hook.reading.fire;
            this._ctx = {
                table: table,
                index: whereCtx.index,
                isPrimKey: (!whereCtx.index || (table.schema.primKey.keyPath && whereCtx.index === table.schema.primKey.name)),
                range: keyRange,
                keysOnly: false,
                dir: "next",
                unique: "",
                algorithm: null,
                filter: null,
                replayFilter: null,
                justLimit: true,
                isMatch: null,
                offset: 0,
                limit: Infinity,
                error: error,
                or: whereCtx.or,
                valueMapper: readingHook !== mirror ? readingHook : null
            };
        });
    }

    function simpleCompare(a, b) {
        return a < b ? -1 : a === b ? 0 : 1;
    }
    function simpleCompareReverse(a, b) {
        return a > b ? -1 : a === b ? 0 : 1;
    }

    function fail(collectionOrWhereClause, err, T) {
        var collection = collectionOrWhereClause instanceof WhereClause ?
            new collectionOrWhereClause.Collection(collectionOrWhereClause) :
            collectionOrWhereClause;
        collection._ctx.error = T ? new T(err) : new TypeError(err);
        return collection;
    }
    function emptyCollection(whereClause) {
        return new whereClause.Collection(whereClause, function () { return rangeEqual(""); }).limit(0);
    }
    function upperFactory(dir) {
        return dir === "next" ?
            function (s) { return s.toUpperCase(); } :
            function (s) { return s.toLowerCase(); };
    }
    function lowerFactory(dir) {
        return dir === "next" ?
            function (s) { return s.toLowerCase(); } :
            function (s) { return s.toUpperCase(); };
    }
    function nextCasing(key, lowerKey, upperNeedle, lowerNeedle, cmp, dir) {
        var length = Math.min(key.length, lowerNeedle.length);
        var llp = -1;
        for (var i = 0; i < length; ++i) {
            var lwrKeyChar = lowerKey[i];
            if (lwrKeyChar !== lowerNeedle[i]) {
                if (cmp(key[i], upperNeedle[i]) < 0)
                    return key.substr(0, i) + upperNeedle[i] + upperNeedle.substr(i + 1);
                if (cmp(key[i], lowerNeedle[i]) < 0)
                    return key.substr(0, i) + lowerNeedle[i] + upperNeedle.substr(i + 1);
                if (llp >= 0)
                    return key.substr(0, llp) + lowerKey[llp] + upperNeedle.substr(llp + 1);
                return null;
            }
            if (cmp(key[i], lwrKeyChar) < 0)
                llp = i;
        }
        if (length < lowerNeedle.length && dir === "next")
            return key + upperNeedle.substr(key.length);
        if (length < key.length && dir === "prev")
            return key.substr(0, upperNeedle.length);
        return (llp < 0 ? null : key.substr(0, llp) + lowerNeedle[llp] + upperNeedle.substr(llp + 1));
    }
    function addIgnoreCaseAlgorithm(whereClause, match, needles, suffix) {
        var upper, lower, compare, upperNeedles, lowerNeedles, direction, nextKeySuffix, needlesLen = needles.length;
        if (!needles.every(function (s) { return typeof s === 'string'; })) {
            return fail(whereClause, STRING_EXPECTED);
        }
        function initDirection(dir) {
            upper = upperFactory(dir);
            lower = lowerFactory(dir);
            compare = (dir === "next" ? simpleCompare : simpleCompareReverse);
            var needleBounds = needles.map(function (needle) {
                return { lower: lower(needle), upper: upper(needle) };
            }).sort(function (a, b) {
                return compare(a.lower, b.lower);
            });
            upperNeedles = needleBounds.map(function (nb) { return nb.upper; });
            lowerNeedles = needleBounds.map(function (nb) { return nb.lower; });
            direction = dir;
            nextKeySuffix = (dir === "next" ? "" : suffix);
        }
        initDirection("next");
        var c = new whereClause.Collection(whereClause, function () { return createRange(upperNeedles[0], lowerNeedles[needlesLen - 1] + suffix); });
        c._ondirectionchange = function (direction) {
            initDirection(direction);
        };
        var firstPossibleNeedle = 0;
        c._addAlgorithm(function (cursor, advance, resolve) {
            var key = cursor.key;
            if (typeof key !== 'string')
                return false;
            var lowerKey = lower(key);
            if (match(lowerKey, lowerNeedles, firstPossibleNeedle)) {
                return true;
            }
            else {
                var lowestPossibleCasing = null;
                for (var i = firstPossibleNeedle; i < needlesLen; ++i) {
                    var casing = nextCasing(key, lowerKey, upperNeedles[i], lowerNeedles[i], compare, direction);
                    if (casing === null && lowestPossibleCasing === null)
                        firstPossibleNeedle = i + 1;
                    else if (lowestPossibleCasing === null || compare(lowestPossibleCasing, casing) > 0) {
                        lowestPossibleCasing = casing;
                    }
                }
                if (lowestPossibleCasing !== null) {
                    advance(function () { cursor.continue(lowestPossibleCasing + nextKeySuffix); });
                }
                else {
                    advance(resolve);
                }
                return false;
            }
        });
        return c;
    }
    function createRange(lower, upper, lowerOpen, upperOpen) {
        return {
            type: 2 ,
            lower: lower,
            upper: upper,
            lowerOpen: lowerOpen,
            upperOpen: upperOpen
        };
    }
    function rangeEqual(value) {
        return {
            type: 1 ,
            lower: value,
            upper: value
        };
    }

    var WhereClause =  (function () {
        function WhereClause() {
        }
        Object.defineProperty(WhereClause.prototype, "Collection", {
            get: function () {
                return this._ctx.table.db.Collection;
            },
            enumerable: false,
            configurable: true
        });
        WhereClause.prototype.between = function (lower, upper, includeLower, includeUpper) {
            includeLower = includeLower !== false;
            includeUpper = includeUpper === true;
            try {
                if ((this._cmp(lower, upper) > 0) ||
                    (this._cmp(lower, upper) === 0 && (includeLower || includeUpper) && !(includeLower && includeUpper)))
                    return emptyCollection(this);
                return new this.Collection(this, function () { return createRange(lower, upper, !includeLower, !includeUpper); });
            }
            catch (e) {
                return fail(this, INVALID_KEY_ARGUMENT);
            }
        };
        WhereClause.prototype.equals = function (value) {
            if (value == null)
                return fail(this, INVALID_KEY_ARGUMENT);
            return new this.Collection(this, function () { return rangeEqual(value); });
        };
        WhereClause.prototype.above = function (value) {
            if (value == null)
                return fail(this, INVALID_KEY_ARGUMENT);
            return new this.Collection(this, function () { return createRange(value, undefined, true); });
        };
        WhereClause.prototype.aboveOrEqual = function (value) {
            if (value == null)
                return fail(this, INVALID_KEY_ARGUMENT);
            return new this.Collection(this, function () { return createRange(value, undefined, false); });
        };
        WhereClause.prototype.below = function (value) {
            if (value == null)
                return fail(this, INVALID_KEY_ARGUMENT);
            return new this.Collection(this, function () { return createRange(undefined, value, false, true); });
        };
        WhereClause.prototype.belowOrEqual = function (value) {
            if (value == null)
                return fail(this, INVALID_KEY_ARGUMENT);
            return new this.Collection(this, function () { return createRange(undefined, value); });
        };
        WhereClause.prototype.startsWith = function (str) {
            if (typeof str !== 'string')
                return fail(this, STRING_EXPECTED);
            return this.between(str, str + maxString, true, true);
        };
        WhereClause.prototype.startsWithIgnoreCase = function (str) {
            if (str === "")
                return this.startsWith(str);
            return addIgnoreCaseAlgorithm(this, function (x, a) { return x.indexOf(a[0]) === 0; }, [str], maxString);
        };
        WhereClause.prototype.equalsIgnoreCase = function (str) {
            return addIgnoreCaseAlgorithm(this, function (x, a) { return x === a[0]; }, [str], "");
        };
        WhereClause.prototype.anyOfIgnoreCase = function () {
            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
            if (set.length === 0)
                return emptyCollection(this);
            return addIgnoreCaseAlgorithm(this, function (x, a) { return a.indexOf(x) !== -1; }, set, "");
        };
        WhereClause.prototype.startsWithAnyOfIgnoreCase = function () {
            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
            if (set.length === 0)
                return emptyCollection(this);
            return addIgnoreCaseAlgorithm(this, function (x, a) { return a.some(function (n) { return x.indexOf(n) === 0; }); }, set, maxString);
        };
        WhereClause.prototype.anyOf = function () {
            var _this = this;
            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
            var compare = this._cmp;
            try {
                set.sort(compare);
            }
            catch (e) {
                return fail(this, INVALID_KEY_ARGUMENT);
            }
            if (set.length === 0)
                return emptyCollection(this);
            var c = new this.Collection(this, function () { return createRange(set[0], set[set.length - 1]); });
            c._ondirectionchange = function (direction) {
                compare = (direction === "next" ?
                    _this._ascending :
                    _this._descending);
                set.sort(compare);
            };
            var i = 0;
            c._addAlgorithm(function (cursor, advance, resolve) {
                var key = cursor.key;
                while (compare(key, set[i]) > 0) {
                    ++i;
                    if (i === set.length) {
                        advance(resolve);
                        return false;
                    }
                }
                if (compare(key, set[i]) === 0) {
                    return true;
                }
                else {
                    advance(function () { cursor.continue(set[i]); });
                    return false;
                }
            });
            return c;
        };
        WhereClause.prototype.notEqual = function (value) {
            return this.inAnyRange([[minKey, value], [value, this.db._maxKey]], { includeLowers: false, includeUppers: false });
        };
        WhereClause.prototype.noneOf = function () {
            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
            if (set.length === 0)
                return new this.Collection(this);
            try {
                set.sort(this._ascending);
            }
            catch (e) {
                return fail(this, INVALID_KEY_ARGUMENT);
            }
            var ranges = set.reduce(function (res, val) { return res ?
                res.concat([[res[res.length - 1][1], val]]) :
                [[minKey, val]]; }, null);
            ranges.push([set[set.length - 1], this.db._maxKey]);
            return this.inAnyRange(ranges, { includeLowers: false, includeUppers: false });
        };
        WhereClause.prototype.inAnyRange = function (ranges, options) {
            var _this = this;
            var cmp = this._cmp, ascending = this._ascending, descending = this._descending, min = this._min, max = this._max;
            if (ranges.length === 0)
                return emptyCollection(this);
            if (!ranges.every(function (range) {
                return range[0] !== undefined &&
                    range[1] !== undefined &&
                    ascending(range[0], range[1]) <= 0;
            })) {
                return fail(this, "First argument to inAnyRange() must be an Array of two-value Arrays [lower,upper] where upper must not be lower than lower", exceptions.InvalidArgument);
            }
            var includeLowers = !options || options.includeLowers !== false;
            var includeUppers = options && options.includeUppers === true;
            function addRange(ranges, newRange) {
                var i = 0, l = ranges.length;
                for (; i < l; ++i) {
                    var range = ranges[i];
                    if (cmp(newRange[0], range[1]) < 0 && cmp(newRange[1], range[0]) > 0) {
                        range[0] = min(range[0], newRange[0]);
                        range[1] = max(range[1], newRange[1]);
                        break;
                    }
                }
                if (i === l)
                    ranges.push(newRange);
                return ranges;
            }
            var sortDirection = ascending;
            function rangeSorter(a, b) { return sortDirection(a[0], b[0]); }
            var set;
            try {
                set = ranges.reduce(addRange, []);
                set.sort(rangeSorter);
            }
            catch (ex) {
                return fail(this, INVALID_KEY_ARGUMENT);
            }
            var rangePos = 0;
            var keyIsBeyondCurrentEntry = includeUppers ?
                function (key) { return ascending(key, set[rangePos][1]) > 0; } :
                function (key) { return ascending(key, set[rangePos][1]) >= 0; };
            var keyIsBeforeCurrentEntry = includeLowers ?
                function (key) { return descending(key, set[rangePos][0]) > 0; } :
                function (key) { return descending(key, set[rangePos][0]) >= 0; };
            function keyWithinCurrentRange(key) {
                return !keyIsBeyondCurrentEntry(key) && !keyIsBeforeCurrentEntry(key);
            }
            var checkKey = keyIsBeyondCurrentEntry;
            var c = new this.Collection(this, function () { return createRange(set[0][0], set[set.length - 1][1], !includeLowers, !includeUppers); });
            c._ondirectionchange = function (direction) {
                if (direction === "next") {
                    checkKey = keyIsBeyondCurrentEntry;
                    sortDirection = ascending;
                }
                else {
                    checkKey = keyIsBeforeCurrentEntry;
                    sortDirection = descending;
                }
                set.sort(rangeSorter);
            };
            c._addAlgorithm(function (cursor, advance, resolve) {
                var key = cursor.key;
                while (checkKey(key)) {
                    ++rangePos;
                    if (rangePos === set.length) {
                        advance(resolve);
                        return false;
                    }
                }
                if (keyWithinCurrentRange(key)) {
                    return true;
                }
                else if (_this._cmp(key, set[rangePos][1]) === 0 || _this._cmp(key, set[rangePos][0]) === 0) {
                    return false;
                }
                else {
                    advance(function () {
                        if (sortDirection === ascending)
                            cursor.continue(set[rangePos][0]);
                        else
                            cursor.continue(set[rangePos][1]);
                    });
                    return false;
                }
            });
            return c;
        };
        WhereClause.prototype.startsWithAnyOf = function () {
            var set = getArrayOf.apply(NO_CHAR_ARRAY, arguments);
            if (!set.every(function (s) { return typeof s === 'string'; })) {
                return fail(this, "startsWithAnyOf() only works with strings");
            }
            if (set.length === 0)
                return emptyCollection(this);
            return this.inAnyRange(set.map(function (str) { return [str, str + maxString]; }));
        };
        return WhereClause;
    }());

    function createWhereClauseConstructor(db) {
        return makeClassConstructor(WhereClause.prototype, function WhereClause(table, index, orCollection) {
            this.db = db;
            this._ctx = {
                table: table,
                index: index === ":id" ? null : index,
                or: orCollection
            };
            this._cmp = this._ascending = cmp;
            this._descending = function (a, b) { return cmp(b, a); };
            this._max = function (a, b) { return cmp(a, b) > 0 ? a : b; };
            this._min = function (a, b) { return cmp(a, b) < 0 ? a : b; };
            this._IDBKeyRange = db._deps.IDBKeyRange;
            if (!this._IDBKeyRange)
                throw new exceptions.MissingAPI();
        });
    }

    function eventRejectHandler(reject) {
        return wrap(function (event) {
            preventDefault(event);
            reject(event.target.error);
            return false;
        });
    }
    function preventDefault(event) {
        if (event.stopPropagation)
            event.stopPropagation();
        if (event.preventDefault)
            event.preventDefault();
    }

    var DEXIE_STORAGE_MUTATED_EVENT_NAME = 'storagemutated';
    var STORAGE_MUTATED_DOM_EVENT_NAME = 'x-storagemutated-1';
    var globalEvents = Events(null, DEXIE_STORAGE_MUTATED_EVENT_NAME);

    var Transaction =  (function () {
        function Transaction() {
        }
        Transaction.prototype._lock = function () {
            assert(!PSD.global);
            ++this._reculock;
            if (this._reculock === 1 && !PSD.global)
                PSD.lockOwnerFor = this;
            return this;
        };
        Transaction.prototype._unlock = function () {
            assert(!PSD.global);
            if (--this._reculock === 0) {
                if (!PSD.global)
                    PSD.lockOwnerFor = null;
                while (this._blockedFuncs.length > 0 && !this._locked()) {
                    var fnAndPSD = this._blockedFuncs.shift();
                    try {
                        usePSD(fnAndPSD[1], fnAndPSD[0]);
                    }
                    catch (e) { }
                }
            }
            return this;
        };
        Transaction.prototype._locked = function () {
            return this._reculock && PSD.lockOwnerFor !== this;
        };
        Transaction.prototype.create = function (idbtrans) {
            var _this = this;
            if (!this.mode)
                return this;
            var idbdb = this.db.idbdb;
            var dbOpenError = this.db._state.dbOpenError;
            assert(!this.idbtrans);
            if (!idbtrans && !idbdb) {
                switch (dbOpenError && dbOpenError.name) {
                    case "DatabaseClosedError":
                        throw new exceptions.DatabaseClosed(dbOpenError);
                    case "MissingAPIError":
                        throw new exceptions.MissingAPI(dbOpenError.message, dbOpenError);
                    default:
                        throw new exceptions.OpenFailed(dbOpenError);
                }
            }
            if (!this.active)
                throw new exceptions.TransactionInactive();
            assert(this._completion._state === null);
            idbtrans = this.idbtrans = idbtrans ||
                (this.db.core
                    ? this.db.core.transaction(this.storeNames, this.mode, { durability: this.chromeTransactionDurability })
                    : idbdb.transaction(this.storeNames, this.mode, { durability: this.chromeTransactionDurability }));
            idbtrans.onerror = wrap(function (ev) {
                preventDefault(ev);
                _this._reject(idbtrans.error);
            });
            idbtrans.onabort = wrap(function (ev) {
                preventDefault(ev);
                _this.active && _this._reject(new exceptions.Abort(idbtrans.error));
                _this.active = false;
                _this.on("abort").fire(ev);
            });
            idbtrans.oncomplete = wrap(function () {
                _this.active = false;
                _this._resolve();
                if ('mutatedParts' in idbtrans) {
                    globalEvents.storagemutated.fire(idbtrans["mutatedParts"]);
                }
            });
            return this;
        };
        Transaction.prototype._promise = function (mode, fn, bWriteLock) {
            var _this = this;
            if (mode === 'readwrite' && this.mode !== 'readwrite')
                return rejection(new exceptions.ReadOnly("Transaction is readonly"));
            if (!this.active)
                return rejection(new exceptions.TransactionInactive());
            if (this._locked()) {
                return new DexiePromise(function (resolve, reject) {
                    _this._blockedFuncs.push([function () {
                            _this._promise(mode, fn, bWriteLock).then(resolve, reject);
                        }, PSD]);
                });
            }
            else if (bWriteLock) {
                return newScope(function () {
                    var p = new DexiePromise(function (resolve, reject) {
                        _this._lock();
                        var rv = fn(resolve, reject, _this);
                        if (rv && rv.then)
                            rv.then(resolve, reject);
                    });
                    p.finally(function () { return _this._unlock(); });
                    p._lib = true;
                    return p;
                });
            }
            else {
                var p = new DexiePromise(function (resolve, reject) {
                    var rv = fn(resolve, reject, _this);
                    if (rv && rv.then)
                        rv.then(resolve, reject);
                });
                p._lib = true;
                return p;
            }
        };
        Transaction.prototype._root = function () {
            return this.parent ? this.parent._root() : this;
        };
        Transaction.prototype.waitFor = function (promiseLike) {
            var root = this._root();
            var promise = DexiePromise.resolve(promiseLike);
            if (root._waitingFor) {
                root._waitingFor = root._waitingFor.then(function () { return promise; });
            }
            else {
                root._waitingFor = promise;
                root._waitingQueue = [];
                var store = root.idbtrans.objectStore(root.storeNames[0]);
                (function spin() {
                    ++root._spinCount;
                    while (root._waitingQueue.length)
                        (root._waitingQueue.shift())();
                    if (root._waitingFor)
                        store.get(-Infinity).onsuccess = spin;
                }());
            }
            var currentWaitPromise = root._waitingFor;
            return new DexiePromise(function (resolve, reject) {
                promise.then(function (res) { return root._waitingQueue.push(wrap(resolve.bind(null, res))); }, function (err) { return root._waitingQueue.push(wrap(reject.bind(null, err))); }).finally(function () {
                    if (root._waitingFor === currentWaitPromise) {
                        root._waitingFor = null;
                    }
                });
            });
        };
        Transaction.prototype.abort = function () {
            if (this.active) {
                this.active = false;
                if (this.idbtrans)
                    this.idbtrans.abort();
                this._reject(new exceptions.Abort());
            }
        };
        Transaction.prototype.table = function (tableName) {
            var memoizedTables = (this._memoizedTables || (this._memoizedTables = {}));
            if (hasOwn(memoizedTables, tableName))
                return memoizedTables[tableName];
            var tableSchema = this.schema[tableName];
            if (!tableSchema) {
                throw new exceptions.NotFound("Table " + tableName + " not part of transaction");
            }
            var transactionBoundTable = new this.db.Table(tableName, tableSchema, this);
            transactionBoundTable.core = this.db.core.table(tableName);
            memoizedTables[tableName] = transactionBoundTable;
            return transactionBoundTable;
        };
        return Transaction;
    }());

    function createTransactionConstructor(db) {
        return makeClassConstructor(Transaction.prototype, function Transaction(mode, storeNames, dbschema, chromeTransactionDurability, parent) {
            var _this = this;
            this.db = db;
            this.mode = mode;
            this.storeNames = storeNames;
            this.schema = dbschema;
            this.chromeTransactionDurability = chromeTransactionDurability;
            this.idbtrans = null;
            this.on = Events(this, "complete", "error", "abort");
            this.parent = parent || null;
            this.active = true;
            this._reculock = 0;
            this._blockedFuncs = [];
            this._resolve = null;
            this._reject = null;
            this._waitingFor = null;
            this._waitingQueue = null;
            this._spinCount = 0;
            this._completion = new DexiePromise(function (resolve, reject) {
                _this._resolve = resolve;
                _this._reject = reject;
            });
            this._completion.then(function () {
                _this.active = false;
                _this.on.complete.fire();
            }, function (e) {
                var wasActive = _this.active;
                _this.active = false;
                _this.on.error.fire(e);
                _this.parent ?
                    _this.parent._reject(e) :
                    wasActive && _this.idbtrans && _this.idbtrans.abort();
                return rejection(e);
            });
        });
    }

    function createIndexSpec(name, keyPath, unique, multi, auto, compound, isPrimKey) {
        return {
            name: name,
            keyPath: keyPath,
            unique: unique,
            multi: multi,
            auto: auto,
            compound: compound,
            src: (unique && !isPrimKey ? '&' : '') + (multi ? '*' : '') + (auto ? "++" : "") + nameFromKeyPath(keyPath)
        };
    }
    function nameFromKeyPath(keyPath) {
        return typeof keyPath === 'string' ?
            keyPath :
            keyPath ? ('[' + [].join.call(keyPath, '+') + ']') : "";
    }

    function createTableSchema(name, primKey, indexes) {
        return {
            name: name,
            primKey: primKey,
            indexes: indexes,
            mappedClass: null,
            idxByName: arrayToObject(indexes, function (index) { return [index.name, index]; })
        };
    }

    function safariMultiStoreFix(storeNames) {
        return storeNames.length === 1 ? storeNames[0] : storeNames;
    }
    var getMaxKey = function (IdbKeyRange) {
        try {
            IdbKeyRange.only([[]]);
            getMaxKey = function () { return [[]]; };
            return [[]];
        }
        catch (e) {
            getMaxKey = function () { return maxString; };
            return maxString;
        }
    };

    function getKeyExtractor(keyPath) {
        if (keyPath == null) {
            return function () { return undefined; };
        }
        else if (typeof keyPath === 'string') {
            return getSinglePathKeyExtractor(keyPath);
        }
        else {
            return function (obj) { return getByKeyPath(obj, keyPath); };
        }
    }
    function getSinglePathKeyExtractor(keyPath) {
        var split = keyPath.split('.');
        if (split.length === 1) {
            return function (obj) { return obj[keyPath]; };
        }
        else {
            return function (obj) { return getByKeyPath(obj, keyPath); };
        }
    }

    function arrayify(arrayLike) {
        return [].slice.call(arrayLike);
    }
    var _id_counter = 0;
    function getKeyPathAlias(keyPath) {
        return keyPath == null ?
            ":id" :
            typeof keyPath === 'string' ?
                keyPath :
                "[".concat(keyPath.join('+'), "]");
    }
    function createDBCore(db, IdbKeyRange, tmpTrans) {
        function extractSchema(db, trans) {
            var tables = arrayify(db.objectStoreNames);
            return {
                schema: {
                    name: db.name,
                    tables: tables.map(function (table) { return trans.objectStore(table); }).map(function (store) {
                        var keyPath = store.keyPath, autoIncrement = store.autoIncrement;
                        var compound = isArray(keyPath);
                        var outbound = keyPath == null;
                        var indexByKeyPath = {};
                        var result = {
                            name: store.name,
                            primaryKey: {
                                name: null,
                                isPrimaryKey: true,
                                outbound: outbound,
                                compound: compound,
                                keyPath: keyPath,
                                autoIncrement: autoIncrement,
                                unique: true,
                                extractKey: getKeyExtractor(keyPath)
                            },
                            indexes: arrayify(store.indexNames).map(function (indexName) { return store.index(indexName); })
                                .map(function (index) {
                                var name = index.name, unique = index.unique, multiEntry = index.multiEntry, keyPath = index.keyPath;
                                var compound = isArray(keyPath);
                                var result = {
                                    name: name,
                                    compound: compound,
                                    keyPath: keyPath,
                                    unique: unique,
                                    multiEntry: multiEntry,
                                    extractKey: getKeyExtractor(keyPath)
                                };
                                indexByKeyPath[getKeyPathAlias(keyPath)] = result;
                                return result;
                            }),
                            getIndexByKeyPath: function (keyPath) { return indexByKeyPath[getKeyPathAlias(keyPath)]; }
                        };
                        indexByKeyPath[":id"] = result.primaryKey;
                        if (keyPath != null) {
                            indexByKeyPath[getKeyPathAlias(keyPath)] = result.primaryKey;
                        }
                        return result;
                    })
                },
                hasGetAll: tables.length > 0 && ('getAll' in trans.objectStore(tables[0])) &&
                    !(typeof navigator !== 'undefined' && /Safari/.test(navigator.userAgent) &&
                        !/(Chrome\/|Edge\/)/.test(navigator.userAgent) &&
                        [].concat(navigator.userAgent.match(/Safari\/(\d*)/))[1] < 604)
            };
        }
        function makeIDBKeyRange(range) {
            if (range.type === 3 )
                return null;
            if (range.type === 4 )
                throw new Error("Cannot convert never type to IDBKeyRange");
            var lower = range.lower, upper = range.upper, lowerOpen = range.lowerOpen, upperOpen = range.upperOpen;
            var idbRange = lower === undefined ?
                upper === undefined ?
                    null :
                    IdbKeyRange.upperBound(upper, !!upperOpen) :
                upper === undefined ?
                    IdbKeyRange.lowerBound(lower, !!lowerOpen) :
                    IdbKeyRange.bound(lower, upper, !!lowerOpen, !!upperOpen);
            return idbRange;
        }
        function createDbCoreTable(tableSchema) {
            var tableName = tableSchema.name;
            function mutate(_a) {
                var trans = _a.trans, type = _a.type, keys = _a.keys, values = _a.values, range = _a.range;
                return new Promise(function (resolve, reject) {
                    resolve = wrap(resolve);
                    var store = trans.objectStore(tableName);
                    var outbound = store.keyPath == null;
                    var isAddOrPut = type === "put" || type === "add";
                    if (!isAddOrPut && type !== 'delete' && type !== 'deleteRange')
                        throw new Error("Invalid operation type: " + type);
                    var length = (keys || values || { length: 1 }).length;
                    if (keys && values && keys.length !== values.length) {
                        throw new Error("Given keys array must have same length as given values array.");
                    }
                    if (length === 0)
                        return resolve({ numFailures: 0, failures: {}, results: [], lastResult: undefined });
                    var req;
                    var reqs = [];
                    var failures = [];
                    var numFailures = 0;
                    var errorHandler = function (event) {
                        ++numFailures;
                        preventDefault(event);
                    };
                    if (type === 'deleteRange') {
                        if (range.type === 4 )
                            return resolve({ numFailures: numFailures, failures: failures, results: [], lastResult: undefined });
                        if (range.type === 3 )
                            reqs.push(req = store.clear());
                        else
                            reqs.push(req = store.delete(makeIDBKeyRange(range)));
                    }
                    else {
                        var _a = isAddOrPut ?
                            outbound ?
                                [values, keys] :
                                [values, null] :
                            [keys, null], args1 = _a[0], args2 = _a[1];
                        if (isAddOrPut) {
                            for (var i = 0; i < length; ++i) {
                                reqs.push(req = (args2 && args2[i] !== undefined ?
                                    store[type](args1[i], args2[i]) :
                                    store[type](args1[i])));
                                req.onerror = errorHandler;
                            }
                        }
                        else {
                            for (var i = 0; i < length; ++i) {
                                reqs.push(req = store[type](args1[i]));
                                req.onerror = errorHandler;
                            }
                        }
                    }
                    var done = function (event) {
                        var lastResult = event.target.result;
                        reqs.forEach(function (req, i) { return req.error != null && (failures[i] = req.error); });
                        resolve({
                            numFailures: numFailures,
                            failures: failures,
                            results: type === "delete" ? keys : reqs.map(function (req) { return req.result; }),
                            lastResult: lastResult
                        });
                    };
                    req.onerror = function (event) {
                        errorHandler(event);
                        done(event);
                    };
                    req.onsuccess = done;
                });
            }
            function openCursor(_a) {
                var trans = _a.trans, values = _a.values, query = _a.query, reverse = _a.reverse, unique = _a.unique;
                return new Promise(function (resolve, reject) {
                    resolve = wrap(resolve);
                    var index = query.index, range = query.range;
                    var store = trans.objectStore(tableName);
                    var source = index.isPrimaryKey ?
                        store :
                        store.index(index.name);
                    var direction = reverse ?
                        unique ?
                            "prevunique" :
                            "prev" :
                        unique ?
                            "nextunique" :
                            "next";
                    var req = values || !('openKeyCursor' in source) ?
                        source.openCursor(makeIDBKeyRange(range), direction) :
                        source.openKeyCursor(makeIDBKeyRange(range), direction);
                    req.onerror = eventRejectHandler(reject);
                    req.onsuccess = wrap(function (ev) {
                        var cursor = req.result;
                        if (!cursor) {
                            resolve(null);
                            return;
                        }
                        cursor.___id = ++_id_counter;
                        cursor.done = false;
                        var _cursorContinue = cursor.continue.bind(cursor);
                        var _cursorContinuePrimaryKey = cursor.continuePrimaryKey;
                        if (_cursorContinuePrimaryKey)
                            _cursorContinuePrimaryKey = _cursorContinuePrimaryKey.bind(cursor);
                        var _cursorAdvance = cursor.advance.bind(cursor);
                        var doThrowCursorIsNotStarted = function () { throw new Error("Cursor not started"); };
                        var doThrowCursorIsStopped = function () { throw new Error("Cursor not stopped"); };
                        cursor.trans = trans;
                        cursor.stop = cursor.continue = cursor.continuePrimaryKey = cursor.advance = doThrowCursorIsNotStarted;
                        cursor.fail = wrap(reject);
                        cursor.next = function () {
                            var _this = this;
                            var gotOne = 1;
                            return this.start(function () { return gotOne-- ? _this.continue() : _this.stop(); }).then(function () { return _this; });
                        };
                        cursor.start = function (callback) {
                            var iterationPromise = new Promise(function (resolveIteration, rejectIteration) {
                                resolveIteration = wrap(resolveIteration);
                                req.onerror = eventRejectHandler(rejectIteration);
                                cursor.fail = rejectIteration;
                                cursor.stop = function (value) {
                                    cursor.stop = cursor.continue = cursor.continuePrimaryKey = cursor.advance = doThrowCursorIsStopped;
                                    resolveIteration(value);
                                };
                            });
                            var guardedCallback = function () {
                                if (req.result) {
                                    try {
                                        callback();
                                    }
                                    catch (err) {
                                        cursor.fail(err);
                                    }
                                }
                                else {
                                    cursor.done = true;
                                    cursor.start = function () { throw new Error("Cursor behind last entry"); };
                                    cursor.stop();
                                }
                            };
                            req.onsuccess = wrap(function (ev) {
                                req.onsuccess = guardedCallback;
                                guardedCallback();
                            });
                            cursor.continue = _cursorContinue;
                            cursor.continuePrimaryKey = _cursorContinuePrimaryKey;
                            cursor.advance = _cursorAdvance;
                            guardedCallback();
                            return iterationPromise;
                        };
                        resolve(cursor);
                    }, reject);
                });
            }
            function query(hasGetAll) {
                return function (request) {
                    return new Promise(function (resolve, reject) {
                        resolve = wrap(resolve);
                        var trans = request.trans, values = request.values, limit = request.limit, query = request.query;
                        var nonInfinitLimit = limit === Infinity ? undefined : limit;
                        var index = query.index, range = query.range;
                        var store = trans.objectStore(tableName);
                        var source = index.isPrimaryKey ? store : store.index(index.name);
                        var idbKeyRange = makeIDBKeyRange(range);
                        if (limit === 0)
                            return resolve({ result: [] });
                        if (hasGetAll) {
                            var req = values ?
                                source.getAll(idbKeyRange, nonInfinitLimit) :
                                source.getAllKeys(idbKeyRange, nonInfinitLimit);
                            req.onsuccess = function (event) { return resolve({ result: event.target.result }); };
                            req.onerror = eventRejectHandler(reject);
                        }
                        else {
                            var count_1 = 0;
                            var req_1 = values || !('openKeyCursor' in source) ?
                                source.openCursor(idbKeyRange) :
                                source.openKeyCursor(idbKeyRange);
                            var result_1 = [];
                            req_1.onsuccess = function (event) {
                                var cursor = req_1.result;
                                if (!cursor)
                                    return resolve({ result: result_1 });
                                result_1.push(values ? cursor.value : cursor.primaryKey);
                                if (++count_1 === limit)
                                    return resolve({ result: result_1 });
                                cursor.continue();
                            };
                            req_1.onerror = eventRejectHandler(reject);
                        }
                    });
                };
            }
            return {
                name: tableName,
                schema: tableSchema,
                mutate: mutate,
                getMany: function (_a) {
                    var trans = _a.trans, keys = _a.keys;
                    return new Promise(function (resolve, reject) {
                        resolve = wrap(resolve);
                        var store = trans.objectStore(tableName);
                        var length = keys.length;
                        var result = new Array(length);
                        var keyCount = 0;
                        var callbackCount = 0;
                        var req;
                        var successHandler = function (event) {
                            var req = event.target;
                            if ((result[req._pos] = req.result) != null)
                                ;
                            if (++callbackCount === keyCount)
                                resolve(result);
                        };
                        var errorHandler = eventRejectHandler(reject);
                        for (var i = 0; i < length; ++i) {
                            var key = keys[i];
                            if (key != null) {
                                req = store.get(keys[i]);
                                req._pos = i;
                                req.onsuccess = successHandler;
                                req.onerror = errorHandler;
                                ++keyCount;
                            }
                        }
                        if (keyCount === 0)
                            resolve(result);
                    });
                },
                get: function (_a) {
                    var trans = _a.trans, key = _a.key;
                    return new Promise(function (resolve, reject) {
                        resolve = wrap(resolve);
                        var store = trans.objectStore(tableName);
                        var req = store.get(key);
                        req.onsuccess = function (event) { return resolve(event.target.result); };
                        req.onerror = eventRejectHandler(reject);
                    });
                },
                query: query(hasGetAll),
                openCursor: openCursor,
                count: function (_a) {
                    var query = _a.query, trans = _a.trans;
                    var index = query.index, range = query.range;
                    return new Promise(function (resolve, reject) {
                        var store = trans.objectStore(tableName);
                        var source = index.isPrimaryKey ? store : store.index(index.name);
                        var idbKeyRange = makeIDBKeyRange(range);
                        var req = idbKeyRange ? source.count(idbKeyRange) : source.count();
                        req.onsuccess = wrap(function (ev) { return resolve(ev.target.result); });
                        req.onerror = eventRejectHandler(reject);
                    });
                }
            };
        }
        var _a = extractSchema(db, tmpTrans), schema = _a.schema, hasGetAll = _a.hasGetAll;
        var tables = schema.tables.map(function (tableSchema) { return createDbCoreTable(tableSchema); });
        var tableMap = {};
        tables.forEach(function (table) { return tableMap[table.name] = table; });
        return {
            stack: "dbcore",
            transaction: db.transaction.bind(db),
            table: function (name) {
                var result = tableMap[name];
                if (!result)
                    throw new Error("Table '".concat(name, "' not found"));
                return tableMap[name];
            },
            MIN_KEY: -Infinity,
            MAX_KEY: getMaxKey(IdbKeyRange),
            schema: schema
        };
    }

    function createMiddlewareStack(stackImpl, middlewares) {
        return middlewares.reduce(function (down, _a) {
            var create = _a.create;
            return (__assign(__assign({}, down), create(down)));
        }, stackImpl);
    }
    function createMiddlewareStacks(middlewares, idbdb, _a, tmpTrans) {
        var IDBKeyRange = _a.IDBKeyRange; _a.indexedDB;
        var dbcore = createMiddlewareStack(createDBCore(idbdb, IDBKeyRange, tmpTrans), middlewares.dbcore);
        return {
            dbcore: dbcore
        };
    }
    function generateMiddlewareStacks(db, tmpTrans) {
        var idbdb = tmpTrans.db;
        var stacks = createMiddlewareStacks(db._middlewares, idbdb, db._deps, tmpTrans);
        db.core = stacks.dbcore;
        db.tables.forEach(function (table) {
            var tableName = table.name;
            if (db.core.schema.tables.some(function (tbl) { return tbl.name === tableName; })) {
                table.core = db.core.table(tableName);
                if (db[tableName] instanceof db.Table) {
                    db[tableName].core = table.core;
                }
            }
        });
    }

    function setApiOnPlace(db, objs, tableNames, dbschema) {
        tableNames.forEach(function (tableName) {
            var schema = dbschema[tableName];
            objs.forEach(function (obj) {
                var propDesc = getPropertyDescriptor(obj, tableName);
                if (!propDesc || ("value" in propDesc && propDesc.value === undefined)) {
                    if (obj === db.Transaction.prototype || obj instanceof db.Transaction) {
                        setProp(obj, tableName, {
                            get: function () { return this.table(tableName); },
                            set: function (value) {
                                defineProperty(this, tableName, { value: value, writable: true, configurable: true, enumerable: true });
                            }
                        });
                    }
                    else {
                        obj[tableName] = new db.Table(tableName, schema);
                    }
                }
            });
        });
    }
    function removeTablesApi(db, objs) {
        objs.forEach(function (obj) {
            for (var key in obj) {
                if (obj[key] instanceof db.Table)
                    delete obj[key];
            }
        });
    }
    function lowerVersionFirst(a, b) {
        return a._cfg.version - b._cfg.version;
    }
    function runUpgraders(db, oldVersion, idbUpgradeTrans, reject) {
        var globalSchema = db._dbSchema;
        if (idbUpgradeTrans.objectStoreNames.contains('$meta') && !globalSchema.$meta) {
            globalSchema.$meta = createTableSchema("$meta", parseIndexSyntax("")[0], []);
            db._storeNames.push('$meta');
        }
        var trans = db._createTransaction('readwrite', db._storeNames, globalSchema);
        trans.create(idbUpgradeTrans);
        trans._completion.catch(reject);
        var rejectTransaction = trans._reject.bind(trans);
        var transless = PSD.transless || PSD;
        newScope(function () {
            PSD.trans = trans;
            PSD.transless = transless;
            if (oldVersion === 0) {
                keys(globalSchema).forEach(function (tableName) {
                    createTable(idbUpgradeTrans, tableName, globalSchema[tableName].primKey, globalSchema[tableName].indexes);
                });
                generateMiddlewareStacks(db, idbUpgradeTrans);
                DexiePromise.follow(function () { return db.on.populate.fire(trans); }).catch(rejectTransaction);
            }
            else {
                generateMiddlewareStacks(db, idbUpgradeTrans);
                return getExistingVersion(db, trans, oldVersion)
                    .then(function (oldVersion) { return updateTablesAndIndexes(db, oldVersion, trans, idbUpgradeTrans); })
                    .catch(rejectTransaction);
            }
        });
    }
    function patchCurrentVersion(db, idbUpgradeTrans) {
        createMissingTables(db._dbSchema, idbUpgradeTrans);
        if (idbUpgradeTrans.db.version % 10 === 0 && !idbUpgradeTrans.objectStoreNames.contains('$meta')) {
            idbUpgradeTrans.db.createObjectStore('$meta').add(Math.ceil((idbUpgradeTrans.db.version / 10) - 1), 'version');
        }
        var globalSchema = buildGlobalSchema(db, db.idbdb, idbUpgradeTrans);
        adjustToExistingIndexNames(db, db._dbSchema, idbUpgradeTrans);
        var diff = getSchemaDiff(globalSchema, db._dbSchema);
        var _loop_1 = function (tableChange) {
            if (tableChange.change.length || tableChange.recreate) {
                console.warn("Unable to patch indexes of table ".concat(tableChange.name, " because it has changes on the type of index or primary key."));
                return { value: void 0 };
            }
            var store = idbUpgradeTrans.objectStore(tableChange.name);
            tableChange.add.forEach(function (idx) {
                if (debug)
                    console.debug("Dexie upgrade patch: Creating missing index ".concat(tableChange.name, ".").concat(idx.src));
                addIndex(store, idx);
            });
        };
        for (var _i = 0, _a = diff.change; _i < _a.length; _i++) {
            var tableChange = _a[_i];
            var state_1 = _loop_1(tableChange);
            if (typeof state_1 === "object")
                return state_1.value;
        }
    }
    function getExistingVersion(db, trans, oldVersion) {
        if (trans.storeNames.includes('$meta')) {
            return trans.table('$meta').get('version').then(function (metaVersion) {
                return metaVersion != null ? metaVersion : oldVersion;
            });
        }
        else {
            return DexiePromise.resolve(oldVersion);
        }
    }
    function updateTablesAndIndexes(db, oldVersion, trans, idbUpgradeTrans) {
        var queue = [];
        var versions = db._versions;
        var globalSchema = db._dbSchema = buildGlobalSchema(db, db.idbdb, idbUpgradeTrans);
        var versToRun = versions.filter(function (v) { return v._cfg.version >= oldVersion; });
        if (versToRun.length === 0) {
            return DexiePromise.resolve();
        }
        versToRun.forEach(function (version) {
            queue.push(function () {
                var oldSchema = globalSchema;
                var newSchema = version._cfg.dbschema;
                adjustToExistingIndexNames(db, oldSchema, idbUpgradeTrans);
                adjustToExistingIndexNames(db, newSchema, idbUpgradeTrans);
                globalSchema = db._dbSchema = newSchema;
                var diff = getSchemaDiff(oldSchema, newSchema);
                diff.add.forEach(function (tuple) {
                    createTable(idbUpgradeTrans, tuple[0], tuple[1].primKey, tuple[1].indexes);
                });
                diff.change.forEach(function (change) {
                    if (change.recreate) {
                        throw new exceptions.Upgrade("Not yet support for changing primary key");
                    }
                    else {
                        var store_1 = idbUpgradeTrans.objectStore(change.name);
                        change.add.forEach(function (idx) { return addIndex(store_1, idx); });
                        change.change.forEach(function (idx) {
                            store_1.deleteIndex(idx.name);
                            addIndex(store_1, idx);
                        });
                        change.del.forEach(function (idxName) { return store_1.deleteIndex(idxName); });
                    }
                });
                var contentUpgrade = version._cfg.contentUpgrade;
                if (contentUpgrade && version._cfg.version > oldVersion) {
                    generateMiddlewareStacks(db, idbUpgradeTrans);
                    trans._memoizedTables = {};
                    var upgradeSchema_1 = shallowClone(newSchema);
                    diff.del.forEach(function (table) {
                        upgradeSchema_1[table] = oldSchema[table];
                    });
                    removeTablesApi(db, [db.Transaction.prototype]);
                    setApiOnPlace(db, [db.Transaction.prototype], keys(upgradeSchema_1), upgradeSchema_1);
                    trans.schema = upgradeSchema_1;
                    var contentUpgradeIsAsync_1 = isAsyncFunction(contentUpgrade);
                    if (contentUpgradeIsAsync_1) {
                        incrementExpectedAwaits();
                    }
                    var returnValue_1;
                    var promiseFollowed = DexiePromise.follow(function () {
                        returnValue_1 = contentUpgrade(trans);
                        if (returnValue_1) {
                            if (contentUpgradeIsAsync_1) {
                                var decrementor = decrementExpectedAwaits.bind(null, null);
                                returnValue_1.then(decrementor, decrementor);
                            }
                        }
                    });
                    return (returnValue_1 && typeof returnValue_1.then === 'function' ?
                        DexiePromise.resolve(returnValue_1) : promiseFollowed.then(function () { return returnValue_1; }));
                }
            });
            queue.push(function (idbtrans) {
                var newSchema = version._cfg.dbschema;
                deleteRemovedTables(newSchema, idbtrans);
                removeTablesApi(db, [db.Transaction.prototype]);
                setApiOnPlace(db, [db.Transaction.prototype], db._storeNames, db._dbSchema);
                trans.schema = db._dbSchema;
            });
            queue.push(function (idbtrans) {
                if (db.idbdb.objectStoreNames.contains('$meta')) {
                    if (Math.ceil(db.idbdb.version / 10) === version._cfg.version) {
                        db.idbdb.deleteObjectStore('$meta');
                        delete db._dbSchema.$meta;
                        db._storeNames = db._storeNames.filter(function (name) { return name !== '$meta'; });
                    }
                    else {
                        idbtrans.objectStore('$meta').put(version._cfg.version, 'version');
                    }
                }
            });
        });
        function runQueue() {
            return queue.length ? DexiePromise.resolve(queue.shift()(trans.idbtrans)).then(runQueue) :
                DexiePromise.resolve();
        }
        return runQueue().then(function () {
            createMissingTables(globalSchema, idbUpgradeTrans);
        });
    }
    function getSchemaDiff(oldSchema, newSchema) {
        var diff = {
            del: [],
            add: [],
            change: []
        };
        var table;
        for (table in oldSchema) {
            if (!newSchema[table])
                diff.del.push(table);
        }
        for (table in newSchema) {
            var oldDef = oldSchema[table], newDef = newSchema[table];
            if (!oldDef) {
                diff.add.push([table, newDef]);
            }
            else {
                var change = {
                    name: table,
                    def: newDef,
                    recreate: false,
                    del: [],
                    add: [],
                    change: []
                };
                if ((
                '' + (oldDef.primKey.keyPath || '')) !== ('' + (newDef.primKey.keyPath || '')) ||
                    (oldDef.primKey.auto !== newDef.primKey.auto)) {
                    change.recreate = true;
                    diff.change.push(change);
                }
                else {
                    var oldIndexes = oldDef.idxByName;
                    var newIndexes = newDef.idxByName;
                    var idxName = void 0;
                    for (idxName in oldIndexes) {
                        if (!newIndexes[idxName])
                            change.del.push(idxName);
                    }
                    for (idxName in newIndexes) {
                        var oldIdx = oldIndexes[idxName], newIdx = newIndexes[idxName];
                        if (!oldIdx)
                            change.add.push(newIdx);
                        else if (oldIdx.src !== newIdx.src)
                            change.change.push(newIdx);
                    }
                    if (change.del.length > 0 || change.add.length > 0 || change.change.length > 0) {
                        diff.change.push(change);
                    }
                }
            }
        }
        return diff;
    }
    function createTable(idbtrans, tableName, primKey, indexes) {
        var store = idbtrans.db.createObjectStore(tableName, primKey.keyPath ?
            { keyPath: primKey.keyPath, autoIncrement: primKey.auto } :
            { autoIncrement: primKey.auto });
        indexes.forEach(function (idx) { return addIndex(store, idx); });
        return store;
    }
    function createMissingTables(newSchema, idbtrans) {
        keys(newSchema).forEach(function (tableName) {
            if (!idbtrans.db.objectStoreNames.contains(tableName)) {
                if (debug)
                    console.debug('Dexie: Creating missing table', tableName);
                createTable(idbtrans, tableName, newSchema[tableName].primKey, newSchema[tableName].indexes);
            }
        });
    }
    function deleteRemovedTables(newSchema, idbtrans) {
        [].slice.call(idbtrans.db.objectStoreNames).forEach(function (storeName) {
            return newSchema[storeName] == null && idbtrans.db.deleteObjectStore(storeName);
        });
    }
    function addIndex(store, idx) {
        store.createIndex(idx.name, idx.keyPath, { unique: idx.unique, multiEntry: idx.multi });
    }
    function buildGlobalSchema(db, idbdb, tmpTrans) {
        var globalSchema = {};
        var dbStoreNames = slice(idbdb.objectStoreNames, 0);
        dbStoreNames.forEach(function (storeName) {
            var store = tmpTrans.objectStore(storeName);
            var keyPath = store.keyPath;
            var primKey = createIndexSpec(nameFromKeyPath(keyPath), keyPath || "", true, false, !!store.autoIncrement, keyPath && typeof keyPath !== "string", true);
            var indexes = [];
            for (var j = 0; j < store.indexNames.length; ++j) {
                var idbindex = store.index(store.indexNames[j]);
                keyPath = idbindex.keyPath;
                var index = createIndexSpec(idbindex.name, keyPath, !!idbindex.unique, !!idbindex.multiEntry, false, keyPath && typeof keyPath !== "string", false);
                indexes.push(index);
            }
            globalSchema[storeName] = createTableSchema(storeName, primKey, indexes);
        });
        return globalSchema;
    }
    function readGlobalSchema(db, idbdb, tmpTrans) {
        db.verno = idbdb.version / 10;
        var globalSchema = db._dbSchema = buildGlobalSchema(db, idbdb, tmpTrans);
        db._storeNames = slice(idbdb.objectStoreNames, 0);
        setApiOnPlace(db, [db._allTables], keys(globalSchema), globalSchema);
    }
    function verifyInstalledSchema(db, tmpTrans) {
        var installedSchema = buildGlobalSchema(db, db.idbdb, tmpTrans);
        var diff = getSchemaDiff(installedSchema, db._dbSchema);
        return !(diff.add.length || diff.change.some(function (ch) { return ch.add.length || ch.change.length; }));
    }
    function adjustToExistingIndexNames(db, schema, idbtrans) {
        var storeNames = idbtrans.db.objectStoreNames;
        for (var i = 0; i < storeNames.length; ++i) {
            var storeName = storeNames[i];
            var store = idbtrans.objectStore(storeName);
            db._hasGetAll = 'getAll' in store;
            for (var j = 0; j < store.indexNames.length; ++j) {
                var indexName = store.indexNames[j];
                var keyPath = store.index(indexName).keyPath;
                var dexieName = typeof keyPath === 'string' ? keyPath : "[" + slice(keyPath).join('+') + "]";
                if (schema[storeName]) {
                    var indexSpec = schema[storeName].idxByName[dexieName];
                    if (indexSpec) {
                        indexSpec.name = indexName;
                        delete schema[storeName].idxByName[dexieName];
                        schema[storeName].idxByName[indexName] = indexSpec;
                    }
                }
            }
        }
        if (typeof navigator !== 'undefined' && /Safari/.test(navigator.userAgent) &&
            !/(Chrome\/|Edge\/)/.test(navigator.userAgent) &&
            _global.WorkerGlobalScope && _global instanceof _global.WorkerGlobalScope &&
            [].concat(navigator.userAgent.match(/Safari\/(\d*)/))[1] < 604) {
            db._hasGetAll = false;
        }
    }
    function parseIndexSyntax(primKeyAndIndexes) {
        return primKeyAndIndexes.split(',').map(function (index, indexNum) {
            index = index.trim();
            var name = index.replace(/([&*]|\+\+)/g, "");
            var keyPath = /^\[/.test(name) ? name.match(/^\[(.*)\]$/)[1].split('+') : name;
            return createIndexSpec(name, keyPath || null, /\&/.test(index), /\*/.test(index), /\+\+/.test(index), isArray(keyPath), indexNum === 0);
        });
    }

    var Version =  (function () {
        function Version() {
        }
        Version.prototype._parseStoresSpec = function (stores, outSchema) {
            keys(stores).forEach(function (tableName) {
                if (stores[tableName] !== null) {
                    var indexes = parseIndexSyntax(stores[tableName]);
                    var primKey = indexes.shift();
                    primKey.unique = true;
                    if (primKey.multi)
                        throw new exceptions.Schema("Primary key cannot be multi-valued");
                    indexes.forEach(function (idx) {
                        if (idx.auto)
                            throw new exceptions.Schema("Only primary key can be marked as autoIncrement (++)");
                        if (!idx.keyPath)
                            throw new exceptions.Schema("Index must have a name and cannot be an empty string");
                    });
                    outSchema[tableName] = createTableSchema(tableName, primKey, indexes);
                }
            });
        };
        Version.prototype.stores = function (stores) {
            var db = this.db;
            this._cfg.storesSource = this._cfg.storesSource ?
                extend(this._cfg.storesSource, stores) :
                stores;
            var versions = db._versions;
            var storesSpec = {};
            var dbschema = {};
            versions.forEach(function (version) {
                extend(storesSpec, version._cfg.storesSource);
                dbschema = (version._cfg.dbschema = {});
                version._parseStoresSpec(storesSpec, dbschema);
            });
            db._dbSchema = dbschema;
            removeTablesApi(db, [db._allTables, db, db.Transaction.prototype]);
            setApiOnPlace(db, [db._allTables, db, db.Transaction.prototype, this._cfg.tables], keys(dbschema), dbschema);
            db._storeNames = keys(dbschema);
            return this;
        };
        Version.prototype.upgrade = function (upgradeFunction) {
            this._cfg.contentUpgrade = promisableChain(this._cfg.contentUpgrade || nop, upgradeFunction);
            return this;
        };
        return Version;
    }());

    function createVersionConstructor(db) {
        return makeClassConstructor(Version.prototype, function Version(versionNumber) {
            this.db = db;
            this._cfg = {
                version: versionNumber,
                storesSource: null,
                dbschema: {},
                tables: {},
                contentUpgrade: null
            };
        });
    }

    function getDbNamesTable(indexedDB, IDBKeyRange) {
        var dbNamesDB = indexedDB["_dbNamesDB"];
        if (!dbNamesDB) {
            dbNamesDB = indexedDB["_dbNamesDB"] = new Dexie$1(DBNAMES_DB, {
                addons: [],
                indexedDB: indexedDB,
                IDBKeyRange: IDBKeyRange,
            });
            dbNamesDB.version(1).stores({ dbnames: "name" });
        }
        return dbNamesDB.table("dbnames");
    }
    function hasDatabasesNative(indexedDB) {
        return indexedDB && typeof indexedDB.databases === "function";
    }
    function getDatabaseNames(_a) {
        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
        return hasDatabasesNative(indexedDB)
            ? Promise.resolve(indexedDB.databases()).then(function (infos) {
                return infos
                    .map(function (info) { return info.name; })
                    .filter(function (name) { return name !== DBNAMES_DB; });
            })
            : getDbNamesTable(indexedDB, IDBKeyRange).toCollection().primaryKeys();
    }
    function _onDatabaseCreated(_a, name) {
        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
        !hasDatabasesNative(indexedDB) &&
            name !== DBNAMES_DB &&
            getDbNamesTable(indexedDB, IDBKeyRange).put({ name: name }).catch(nop);
    }
    function _onDatabaseDeleted(_a, name) {
        var indexedDB = _a.indexedDB, IDBKeyRange = _a.IDBKeyRange;
        !hasDatabasesNative(indexedDB) &&
            name !== DBNAMES_DB &&
            getDbNamesTable(indexedDB, IDBKeyRange).delete(name).catch(nop);
    }

    function vip(fn) {
        return newScope(function () {
            PSD.letThrough = true;
            return fn();
        });
    }

    function idbReady() {
        var isSafari = !navigator.userAgentData &&
            /Safari\//.test(navigator.userAgent) &&
            !/Chrom(e|ium)\//.test(navigator.userAgent);
        if (!isSafari || !indexedDB.databases)
            return Promise.resolve();
        var intervalId;
        return new Promise(function (resolve) {
            var tryIdb = function () { return indexedDB.databases().finally(resolve); };
            intervalId = setInterval(tryIdb, 100);
            tryIdb();
        }).finally(function () { return clearInterval(intervalId); });
    }

    var _a;
    function isEmptyRange(node) {
        return !("from" in node);
    }
    var RangeSet = function (fromOrTree, to) {
        if (this) {
            extend(this, arguments.length ? { d: 1, from: fromOrTree, to: arguments.length > 1 ? to : fromOrTree } : { d: 0 });
        }
        else {
            var rv = new RangeSet();
            if (fromOrTree && ("d" in fromOrTree)) {
                extend(rv, fromOrTree);
            }
            return rv;
        }
    };
    props(RangeSet.prototype, (_a = {
            add: function (rangeSet) {
                mergeRanges(this, rangeSet);
                return this;
            },
            addKey: function (key) {
                addRange(this, key, key);
                return this;
            },
            addKeys: function (keys) {
                var _this = this;
                keys.forEach(function (key) { return addRange(_this, key, key); });
                return this;
            },
            hasKey: function (key) {
                var node = getRangeSetIterator(this).next(key).value;
                return node && cmp(node.from, key) <= 0 && cmp(node.to, key) >= 0;
            }
        },
        _a[iteratorSymbol] = function () {
            return getRangeSetIterator(this);
        },
        _a));
    function addRange(target, from, to) {
        var diff = cmp(from, to);
        if (isNaN(diff))
            return;
        if (diff > 0)
            throw RangeError();
        if (isEmptyRange(target))
            return extend(target, { from: from, to: to, d: 1 });
        var left = target.l;
        var right = target.r;
        if (cmp(to, target.from) < 0) {
            left
                ? addRange(left, from, to)
                : (target.l = { from: from, to: to, d: 1, l: null, r: null });
            return rebalance(target);
        }
        if (cmp(from, target.to) > 0) {
            right
                ? addRange(right, from, to)
                : (target.r = { from: from, to: to, d: 1, l: null, r: null });
            return rebalance(target);
        }
        if (cmp(from, target.from) < 0) {
            target.from = from;
            target.l = null;
            target.d = right ? right.d + 1 : 1;
        }
        if (cmp(to, target.to) > 0) {
            target.to = to;
            target.r = null;
            target.d = target.l ? target.l.d + 1 : 1;
        }
        var rightWasCutOff = !target.r;
        if (left && !target.l) {
            mergeRanges(target, left);
        }
        if (right && rightWasCutOff) {
            mergeRanges(target, right);
        }
    }
    function mergeRanges(target, newSet) {
        function _addRangeSet(target, _a) {
            var from = _a.from, to = _a.to, l = _a.l, r = _a.r;
            addRange(target, from, to);
            if (l)
                _addRangeSet(target, l);
            if (r)
                _addRangeSet(target, r);
        }
        if (!isEmptyRange(newSet))
            _addRangeSet(target, newSet);
    }
    function rangesOverlap(rangeSet1, rangeSet2) {
        var i1 = getRangeSetIterator(rangeSet2);
        var nextResult1 = i1.next();
        if (nextResult1.done)
            return false;
        var a = nextResult1.value;
        var i2 = getRangeSetIterator(rangeSet1);
        var nextResult2 = i2.next(a.from);
        var b = nextResult2.value;
        while (!nextResult1.done && !nextResult2.done) {
            if (cmp(b.from, a.to) <= 0 && cmp(b.to, a.from) >= 0)
                return true;
            cmp(a.from, b.from) < 0
                ? (a = (nextResult1 = i1.next(b.from)).value)
                : (b = (nextResult2 = i2.next(a.from)).value);
        }
        return false;
    }
    function getRangeSetIterator(node) {
        var state = isEmptyRange(node) ? null : { s: 0, n: node };
        return {
            next: function (key) {
                var keyProvided = arguments.length > 0;
                while (state) {
                    switch (state.s) {
                        case 0:
                            state.s = 1;
                            if (keyProvided) {
                                while (state.n.l && cmp(key, state.n.from) < 0)
                                    state = { up: state, n: state.n.l, s: 1 };
                            }
                            else {
                                while (state.n.l)
                                    state = { up: state, n: state.n.l, s: 1 };
                            }
                        case 1:
                            state.s = 2;
                            if (!keyProvided || cmp(key, state.n.to) <= 0)
                                return { value: state.n, done: false };
                        case 2:
                            if (state.n.r) {
                                state.s = 3;
                                state = { up: state, n: state.n.r, s: 0 };
                                continue;
                            }
                        case 3:
                            state = state.up;
                    }
                }
                return { done: true };
            },
        };
    }
    function rebalance(target) {
        var _a, _b;
        var diff = (((_a = target.r) === null || _a === void 0 ? void 0 : _a.d) || 0) - (((_b = target.l) === null || _b === void 0 ? void 0 : _b.d) || 0);
        var r = diff > 1 ? "r" : diff < -1 ? "l" : "";
        if (r) {
            var l = r === "r" ? "l" : "r";
            var rootClone = __assign({}, target);
            var oldRootRight = target[r];
            target.from = oldRootRight.from;
            target.to = oldRootRight.to;
            target[r] = oldRootRight[r];
            rootClone[r] = oldRootRight[l];
            target[l] = rootClone;
            rootClone.d = computeDepth(rootClone);
        }
        target.d = computeDepth(target);
    }
    function computeDepth(_a) {
        var r = _a.r, l = _a.l;
        return (r ? (l ? Math.max(r.d, l.d) : r.d) : l ? l.d : 0) + 1;
    }

    function extendObservabilitySet(target, newSet) {
        keys(newSet).forEach(function (part) {
            if (target[part])
                mergeRanges(target[part], newSet[part]);
            else
                target[part] = cloneSimpleObjectTree(newSet[part]);
        });
        return target;
    }

    function obsSetsOverlap(os1, os2) {
        return os1.all || os2.all || Object.keys(os1).some(function (key) { return os2[key] && rangesOverlap(os2[key], os1[key]); });
    }

    var cache = {};

    var unsignaledParts = {};
    var isTaskEnqueued = false;
    function signalSubscribersLazily(part, optimistic) {
        extendObservabilitySet(unsignaledParts, part);
        if (!isTaskEnqueued) {
            isTaskEnqueued = true;
            setTimeout(function () {
                isTaskEnqueued = false;
                var parts = unsignaledParts;
                unsignaledParts = {};
                signalSubscribersNow(parts, false);
            }, 0);
        }
    }
    function signalSubscribersNow(updatedParts, deleteAffectedCacheEntries) {
        if (deleteAffectedCacheEntries === void 0) { deleteAffectedCacheEntries = false; }
        var queriesToSignal = new Set();
        if (updatedParts.all) {
            for (var _i = 0, _a = Object.values(cache); _i < _a.length; _i++) {
                var tblCache = _a[_i];
                collectTableSubscribers(tblCache, updatedParts, queriesToSignal, deleteAffectedCacheEntries);
            }
        }
        else {
            for (var key in updatedParts) {
                var parts = /^idb\:\/\/(.*)\/(.*)\//.exec(key);
                if (parts) {
                    var dbName = parts[1], tableName = parts[2];
                    var tblCache = cache["idb://".concat(dbName, "/").concat(tableName)];
                    if (tblCache)
                        collectTableSubscribers(tblCache, updatedParts, queriesToSignal, deleteAffectedCacheEntries);
                }
            }
        }
        queriesToSignal.forEach(function (requery) { return requery(); });
    }
    function collectTableSubscribers(tblCache, updatedParts, outQueriesToSignal, deleteAffectedCacheEntries) {
        var updatedEntryLists = [];
        for (var _i = 0, _a = Object.entries(tblCache.queries.query); _i < _a.length; _i++) {
            var _b = _a[_i], indexName = _b[0], entries = _b[1];
            var filteredEntries = [];
            for (var _c = 0, entries_1 = entries; _c < entries_1.length; _c++) {
                var entry = entries_1[_c];
                if (obsSetsOverlap(updatedParts, entry.obsSet)) {
                    entry.subscribers.forEach(function (requery) { return outQueriesToSignal.add(requery); });
                }
                else if (deleteAffectedCacheEntries) {
                    filteredEntries.push(entry);
                }
            }
            if (deleteAffectedCacheEntries)
                updatedEntryLists.push([indexName, filteredEntries]);
        }
        if (deleteAffectedCacheEntries) {
            for (var _d = 0, updatedEntryLists_1 = updatedEntryLists; _d < updatedEntryLists_1.length; _d++) {
                var _e = updatedEntryLists_1[_d], indexName = _e[0], filteredEntries = _e[1];
                tblCache.queries.query[indexName] = filteredEntries;
            }
        }
    }

    function dexieOpen(db) {
        var state = db._state;
        var indexedDB = db._deps.indexedDB;
        if (state.isBeingOpened || db.idbdb)
            return state.dbReadyPromise.then(function () { return state.dbOpenError ?
                rejection(state.dbOpenError) :
                db; });
        state.isBeingOpened = true;
        state.dbOpenError = null;
        state.openComplete = false;
        var openCanceller = state.openCanceller;
        var nativeVerToOpen = Math.round(db.verno * 10);
        var schemaPatchMode = false;
        function throwIfCancelled() {
            if (state.openCanceller !== openCanceller)
                throw new exceptions.DatabaseClosed('db.open() was cancelled');
        }
        var resolveDbReady = state.dbReadyResolve,
        upgradeTransaction = null, wasCreated = false;
        var tryOpenDB = function () { return new DexiePromise(function (resolve, reject) {
            throwIfCancelled();
            if (!indexedDB)
                throw new exceptions.MissingAPI();
            var dbName = db.name;
            var req = state.autoSchema || !nativeVerToOpen ?
                indexedDB.open(dbName) :
                indexedDB.open(dbName, nativeVerToOpen);
            if (!req)
                throw new exceptions.MissingAPI();
            req.onerror = eventRejectHandler(reject);
            req.onblocked = wrap(db._fireOnBlocked);
            req.onupgradeneeded = wrap(function (e) {
                upgradeTransaction = req.transaction;
                if (state.autoSchema && !db._options.allowEmptyDB) {
                    req.onerror = preventDefault;
                    upgradeTransaction.abort();
                    req.result.close();
                    var delreq = indexedDB.deleteDatabase(dbName);
                    delreq.onsuccess = delreq.onerror = wrap(function () {
                        reject(new exceptions.NoSuchDatabase("Database ".concat(dbName, " doesnt exist")));
                    });
                }
                else {
                    upgradeTransaction.onerror = eventRejectHandler(reject);
                    var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion;
                    wasCreated = oldVer < 1;
                    db.idbdb = req.result;
                    if (schemaPatchMode) {
                        patchCurrentVersion(db, upgradeTransaction);
                    }
                    runUpgraders(db, oldVer / 10, upgradeTransaction, reject);
                }
            }, reject);
            req.onsuccess = wrap(function () {
                upgradeTransaction = null;
                var idbdb = db.idbdb = req.result;
                var objectStoreNames = slice(idbdb.objectStoreNames);
                if (objectStoreNames.length > 0)
                    try {
                        var tmpTrans = idbdb.transaction(safariMultiStoreFix(objectStoreNames), 'readonly');
                        if (state.autoSchema)
                            readGlobalSchema(db, idbdb, tmpTrans);
                        else {
                            adjustToExistingIndexNames(db, db._dbSchema, tmpTrans);
                            if (!verifyInstalledSchema(db, tmpTrans) && !schemaPatchMode) {
                                console.warn("Dexie SchemaDiff: Schema was extended without increasing the number passed to db.version(). Dexie will add missing parts and increment native version number to workaround this.");
                                idbdb.close();
                                nativeVerToOpen = idbdb.version + 1;
                                schemaPatchMode = true;
                                return resolve(tryOpenDB());
                            }
                        }
                        generateMiddlewareStacks(db, tmpTrans);
                    }
                    catch (e) {
                    }
                connections.push(db);
                idbdb.onversionchange = wrap(function (ev) {
                    state.vcFired = true;
                    db.on("versionchange").fire(ev);
                });
                idbdb.onclose = wrap(function (ev) {
                    db.on("close").fire(ev);
                });
                if (wasCreated)
                    _onDatabaseCreated(db._deps, dbName);
                resolve();
            }, reject);
        }).catch(function (err) {
            switch (err === null || err === void 0 ? void 0 : err.name) {
                case "UnknownError":
                    if (state.PR1398_maxLoop > 0) {
                        state.PR1398_maxLoop--;
                        console.warn('Dexie: Workaround for Chrome UnknownError on open()');
                        return tryOpenDB();
                    }
                    break;
                case "VersionError":
                    if (nativeVerToOpen > 0) {
                        nativeVerToOpen = 0;
                        return tryOpenDB();
                    }
                    break;
            }
            return DexiePromise.reject(err);
        }); };
        return DexiePromise.race([
            openCanceller,
            (typeof navigator === 'undefined' ? DexiePromise.resolve() : idbReady()).then(tryOpenDB)
        ]).then(function () {
            throwIfCancelled();
            state.onReadyBeingFired = [];
            return DexiePromise.resolve(vip(function () { return db.on.ready.fire(db.vip); })).then(function fireRemainders() {
                if (state.onReadyBeingFired.length > 0) {
                    var remainders_1 = state.onReadyBeingFired.reduce(promisableChain, nop);
                    state.onReadyBeingFired = [];
                    return DexiePromise.resolve(vip(function () { return remainders_1(db.vip); })).then(fireRemainders);
                }
            });
        }).finally(function () {
            if (state.openCanceller === openCanceller) {
                state.onReadyBeingFired = null;
                state.isBeingOpened = false;
            }
        }).catch(function (err) {
            state.dbOpenError = err;
            try {
                upgradeTransaction && upgradeTransaction.abort();
            }
            catch (_a) { }
            if (openCanceller === state.openCanceller) {
                db._close();
            }
            return rejection(err);
        }).finally(function () {
            state.openComplete = true;
            resolveDbReady();
        }).then(function () {
            if (wasCreated) {
                var everything_1 = {};
                db.tables.forEach(function (table) {
                    table.schema.indexes.forEach(function (idx) {
                        if (idx.name)
                            everything_1["idb://".concat(db.name, "/").concat(table.name, "/").concat(idx.name)] = new RangeSet(-Infinity, [[[]]]);
                    });
                    everything_1["idb://".concat(db.name, "/").concat(table.name, "/")] = everything_1["idb://".concat(db.name, "/").concat(table.name, "/:dels")] = new RangeSet(-Infinity, [[[]]]);
                });
                globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME).fire(everything_1);
                signalSubscribersNow(everything_1, true);
            }
            return db;
        });
    }

    function awaitIterator(iterator) {
        var callNext = function (result) { return iterator.next(result); }, doThrow = function (error) { return iterator.throw(error); }, onSuccess = step(callNext), onError = step(doThrow);
        function step(getNext) {
            return function (val) {
                var next = getNext(val), value = next.value;
                return next.done ? value :
                    (!value || typeof value.then !== 'function' ?
                        isArray(value) ? Promise.all(value).then(onSuccess, onError) : onSuccess(value) :
                        value.then(onSuccess, onError));
            };
        }
        return step(callNext)();
    }

    function extractTransactionArgs(mode, _tableArgs_, scopeFunc) {
        var i = arguments.length;
        if (i < 2)
            throw new exceptions.InvalidArgument("Too few arguments");
        var args = new Array(i - 1);
        while (--i)
            args[i - 1] = arguments[i];
        scopeFunc = args.pop();
        var tables = flatten(args);
        return [mode, tables, scopeFunc];
    }
    function enterTransactionScope(db, mode, storeNames, parentTransaction, scopeFunc) {
        return DexiePromise.resolve().then(function () {
            var transless = PSD.transless || PSD;
            var trans = db._createTransaction(mode, storeNames, db._dbSchema, parentTransaction);
            trans.explicit = true;
            var zoneProps = {
                trans: trans,
                transless: transless
            };
            if (parentTransaction) {
                trans.idbtrans = parentTransaction.idbtrans;
            }
            else {
                try {
                    trans.create();
                    trans.idbtrans._explicit = true;
                    db._state.PR1398_maxLoop = 3;
                }
                catch (ex) {
                    if (ex.name === errnames.InvalidState && db.isOpen() && --db._state.PR1398_maxLoop > 0) {
                        console.warn('Dexie: Need to reopen db');
                        db.close({ disableAutoOpen: false });
                        return db.open().then(function () { return enterTransactionScope(db, mode, storeNames, null, scopeFunc); });
                    }
                    return rejection(ex);
                }
            }
            var scopeFuncIsAsync = isAsyncFunction(scopeFunc);
            if (scopeFuncIsAsync) {
                incrementExpectedAwaits();
            }
            var returnValue;
            var promiseFollowed = DexiePromise.follow(function () {
                returnValue = scopeFunc.call(trans, trans);
                if (returnValue) {
                    if (scopeFuncIsAsync) {
                        var decrementor = decrementExpectedAwaits.bind(null, null);
                        returnValue.then(decrementor, decrementor);
                    }
                    else if (typeof returnValue.next === 'function' && typeof returnValue.throw === 'function') {
                        returnValue = awaitIterator(returnValue);
                    }
                }
            }, zoneProps);
            return (returnValue && typeof returnValue.then === 'function' ?
                DexiePromise.resolve(returnValue).then(function (x) { return trans.active ?
                    x
                    : rejection(new exceptions.PrematureCommit("Transaction committed too early. See http://bit.ly/2kdckMn")); })
                : promiseFollowed.then(function () { return returnValue; })).then(function (x) {
                if (parentTransaction)
                    trans._resolve();
                return trans._completion.then(function () { return x; });
            }).catch(function (e) {
                trans._reject(e);
                return rejection(e);
            });
        });
    }

    function pad(a, value, count) {
        var result = isArray(a) ? a.slice() : [a];
        for (var i = 0; i < count; ++i)
            result.push(value);
        return result;
    }
    function createVirtualIndexMiddleware(down) {
        return __assign(__assign({}, down), { table: function (tableName) {
                var table = down.table(tableName);
                var schema = table.schema;
                var indexLookup = {};
                var allVirtualIndexes = [];
                function addVirtualIndexes(keyPath, keyTail, lowLevelIndex) {
                    var keyPathAlias = getKeyPathAlias(keyPath);
                    var indexList = (indexLookup[keyPathAlias] = indexLookup[keyPathAlias] || []);
                    var keyLength = keyPath == null ? 0 : typeof keyPath === 'string' ? 1 : keyPath.length;
                    var isVirtual = keyTail > 0;
                    var virtualIndex = __assign(__assign({}, lowLevelIndex), { name: isVirtual
                            ? "".concat(keyPathAlias, "(virtual-from:").concat(lowLevelIndex.name, ")")
                            : lowLevelIndex.name, lowLevelIndex: lowLevelIndex, isVirtual: isVirtual, keyTail: keyTail, keyLength: keyLength, extractKey: getKeyExtractor(keyPath), unique: !isVirtual && lowLevelIndex.unique });
                    indexList.push(virtualIndex);
                    if (!virtualIndex.isPrimaryKey) {
                        allVirtualIndexes.push(virtualIndex);
                    }
                    if (keyLength > 1) {
                        var virtualKeyPath = keyLength === 2 ?
                            keyPath[0] :
                            keyPath.slice(0, keyLength - 1);
                        addVirtualIndexes(virtualKeyPath, keyTail + 1, lowLevelIndex);
                    }
                    indexList.sort(function (a, b) { return a.keyTail - b.keyTail; });
                    return virtualIndex;
                }
                var primaryKey = addVirtualIndexes(schema.primaryKey.keyPath, 0, schema.primaryKey);
                indexLookup[":id"] = [primaryKey];
                for (var _i = 0, _a = schema.indexes; _i < _a.length; _i++) {
                    var index = _a[_i];
                    addVirtualIndexes(index.keyPath, 0, index);
                }
                function findBestIndex(keyPath) {
                    var result = indexLookup[getKeyPathAlias(keyPath)];
                    return result && result[0];
                }
                function translateRange(range, keyTail) {
                    return {
                        type: range.type === 1  ?
                            2  :
                            range.type,
                        lower: pad(range.lower, range.lowerOpen ? down.MAX_KEY : down.MIN_KEY, keyTail),
                        lowerOpen: true,
                        upper: pad(range.upper, range.upperOpen ? down.MIN_KEY : down.MAX_KEY, keyTail),
                        upperOpen: true
                    };
                }
                function translateRequest(req) {
                    var index = req.query.index;
                    return index.isVirtual ? __assign(__assign({}, req), { query: {
                            index: index.lowLevelIndex,
                            range: translateRange(req.query.range, index.keyTail)
                        } }) : req;
                }
                var result = __assign(__assign({}, table), { schema: __assign(__assign({}, schema), { primaryKey: primaryKey, indexes: allVirtualIndexes, getIndexByKeyPath: findBestIndex }), count: function (req) {
                        return table.count(translateRequest(req));
                    }, query: function (req) {
                        return table.query(translateRequest(req));
                    }, openCursor: function (req) {
                        var _a = req.query.index, keyTail = _a.keyTail, isVirtual = _a.isVirtual, keyLength = _a.keyLength;
                        if (!isVirtual)
                            return table.openCursor(req);
                        function createVirtualCursor(cursor) {
                            function _continue(key) {
                                key != null ?
                                    cursor.continue(pad(key, req.reverse ? down.MAX_KEY : down.MIN_KEY, keyTail)) :
                                    req.unique ?
                                        cursor.continue(cursor.key.slice(0, keyLength)
                                            .concat(req.reverse
                                            ? down.MIN_KEY
                                            : down.MAX_KEY, keyTail)) :
                                        cursor.continue();
                            }
                            var virtualCursor = Object.create(cursor, {
                                continue: { value: _continue },
                                continuePrimaryKey: {
                                    value: function (key, primaryKey) {
                                        cursor.continuePrimaryKey(pad(key, down.MAX_KEY, keyTail), primaryKey);
                                    }
                                },
                                primaryKey: {
                                    get: function () {
                                        return cursor.primaryKey;
                                    }
                                },
                                key: {
                                    get: function () {
                                        var key = cursor.key;
                                        return keyLength === 1 ?
                                            key[0] :
                                            key.slice(0, keyLength);
                                    }
                                },
                                value: {
                                    get: function () {
                                        return cursor.value;
                                    }
                                }
                            });
                            return virtualCursor;
                        }
                        return table.openCursor(translateRequest(req))
                            .then(function (cursor) { return cursor && createVirtualCursor(cursor); });
                    } });
                return result;
            } });
    }
    var virtualIndexMiddleware = {
        stack: "dbcore",
        name: "VirtualIndexMiddleware",
        level: 1,
        create: createVirtualIndexMiddleware
    };

    function getObjectDiff(a, b, rv, prfx) {
        rv = rv || {};
        prfx = prfx || '';
        keys(a).forEach(function (prop) {
            if (!hasOwn(b, prop)) {
                rv[prfx + prop] = undefined;
            }
            else {
                var ap = a[prop], bp = b[prop];
                if (typeof ap === 'object' && typeof bp === 'object' && ap && bp) {
                    var apTypeName = toStringTag(ap);
                    var bpTypeName = toStringTag(bp);
                    if (apTypeName !== bpTypeName) {
                        rv[prfx + prop] = b[prop];
                    }
                    else if (apTypeName === 'Object') {
                        getObjectDiff(ap, bp, rv, prfx + prop + '.');
                    }
                    else if (ap !== bp) {
                        rv[prfx + prop] = b[prop];
                    }
                }
                else if (ap !== bp)
                    rv[prfx + prop] = b[prop];
            }
        });
        keys(b).forEach(function (prop) {
            if (!hasOwn(a, prop)) {
                rv[prfx + prop] = b[prop];
            }
        });
        return rv;
    }

    function getEffectiveKeys(primaryKey, req) {
        if (req.type === 'delete')
            return req.keys;
        return req.keys || req.values.map(primaryKey.extractKey);
    }

    var hooksMiddleware = {
        stack: "dbcore",
        name: "HooksMiddleware",
        level: 2,
        create: function (downCore) { return (__assign(__assign({}, downCore), { table: function (tableName) {
                var downTable = downCore.table(tableName);
                var primaryKey = downTable.schema.primaryKey;
                var tableMiddleware = __assign(__assign({}, downTable), { mutate: function (req) {
                        var dxTrans = PSD.trans;
                        var _a = dxTrans.table(tableName).hook, deleting = _a.deleting, creating = _a.creating, updating = _a.updating;
                        switch (req.type) {
                            case 'add':
                                if (creating.fire === nop)
                                    break;
                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
                            case 'put':
                                if (creating.fire === nop && updating.fire === nop)
                                    break;
                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
                            case 'delete':
                                if (deleting.fire === nop)
                                    break;
                                return dxTrans._promise('readwrite', function () { return addPutOrDelete(req); }, true);
                            case 'deleteRange':
                                if (deleting.fire === nop)
                                    break;
                                return dxTrans._promise('readwrite', function () { return deleteRange(req); }, true);
                        }
                        return downTable.mutate(req);
                        function addPutOrDelete(req) {
                            var dxTrans = PSD.trans;
                            var keys = req.keys || getEffectiveKeys(primaryKey, req);
                            if (!keys)
                                throw new Error("Keys missing");
                            req = req.type === 'add' || req.type === 'put' ? __assign(__assign({}, req), { keys: keys }) : __assign({}, req);
                            if (req.type !== 'delete')
                                req.values = __spreadArray([], req.values, true);
                            if (req.keys)
                                req.keys = __spreadArray([], req.keys, true);
                            return getExistingValues(downTable, req, keys).then(function (existingValues) {
                                var contexts = keys.map(function (key, i) {
                                    var existingValue = existingValues[i];
                                    var ctx = { onerror: null, onsuccess: null };
                                    if (req.type === 'delete') {
                                        deleting.fire.call(ctx, key, existingValue, dxTrans);
                                    }
                                    else if (req.type === 'add' || existingValue === undefined) {
                                        var generatedPrimaryKey = creating.fire.call(ctx, key, req.values[i], dxTrans);
                                        if (key == null && generatedPrimaryKey != null) {
                                            key = generatedPrimaryKey;
                                            req.keys[i] = key;
                                            if (!primaryKey.outbound) {
                                                setByKeyPath(req.values[i], primaryKey.keyPath, key);
                                            }
                                        }
                                    }
                                    else {
                                        var objectDiff = getObjectDiff(existingValue, req.values[i]);
                                        var additionalChanges_1 = updating.fire.call(ctx, objectDiff, key, existingValue, dxTrans);
                                        if (additionalChanges_1) {
                                            var requestedValue_1 = req.values[i];
                                            Object.keys(additionalChanges_1).forEach(function (keyPath) {
                                                if (hasOwn(requestedValue_1, keyPath)) {
                                                    requestedValue_1[keyPath] = additionalChanges_1[keyPath];
                                                }
                                                else {
                                                    setByKeyPath(requestedValue_1, keyPath, additionalChanges_1[keyPath]);
                                                }
                                            });
                                        }
                                    }
                                    return ctx;
                                });
                                return downTable.mutate(req).then(function (_a) {
                                    var failures = _a.failures, results = _a.results, numFailures = _a.numFailures, lastResult = _a.lastResult;
                                    for (var i = 0; i < keys.length; ++i) {
                                        var primKey = results ? results[i] : keys[i];
                                        var ctx = contexts[i];
                                        if (primKey == null) {
                                            ctx.onerror && ctx.onerror(failures[i]);
                                        }
                                        else {
                                            ctx.onsuccess && ctx.onsuccess(req.type === 'put' && existingValues[i] ?
                                                req.values[i] :
                                                primKey
                                            );
                                        }
                                    }
                                    return { failures: failures, results: results, numFailures: numFailures, lastResult: lastResult };
                                }).catch(function (error) {
                                    contexts.forEach(function (ctx) { return ctx.onerror && ctx.onerror(error); });
                                    return Promise.reject(error);
                                });
                            });
                        }
                        function deleteRange(req) {
                            return deleteNextChunk(req.trans, req.range, 10000);
                        }
                        function deleteNextChunk(trans, range, limit) {
                            return downTable.query({ trans: trans, values: false, query: { index: primaryKey, range: range }, limit: limit })
                                .then(function (_a) {
                                var result = _a.result;
                                return addPutOrDelete({ type: 'delete', keys: result, trans: trans }).then(function (res) {
                                    if (res.numFailures > 0)
                                        return Promise.reject(res.failures[0]);
                                    if (result.length < limit) {
                                        return { failures: [], numFailures: 0, lastResult: undefined };
                                    }
                                    else {
                                        return deleteNextChunk(trans, __assign(__assign({}, range), { lower: result[result.length - 1], lowerOpen: true }), limit);
                                    }
                                });
                            });
                        }
                    } });
                return tableMiddleware;
            } })); }
    };
    function getExistingValues(table, req, effectiveKeys) {
        return req.type === "add"
            ? Promise.resolve([])
            : table.getMany({ trans: req.trans, keys: effectiveKeys, cache: "immutable" });
    }

    function getFromTransactionCache(keys, cache, clone) {
        try {
            if (!cache)
                return null;
            if (cache.keys.length < keys.length)
                return null;
            var result = [];
            for (var i = 0, j = 0; i < cache.keys.length && j < keys.length; ++i) {
                if (cmp(cache.keys[i], keys[j]) !== 0)
                    continue;
                result.push(clone ? deepClone(cache.values[i]) : cache.values[i]);
                ++j;
            }
            return result.length === keys.length ? result : null;
        }
        catch (_a) {
            return null;
        }
    }
    var cacheExistingValuesMiddleware = {
        stack: "dbcore",
        level: -1,
        create: function (core) {
            return {
                table: function (tableName) {
                    var table = core.table(tableName);
                    return __assign(__assign({}, table), { getMany: function (req) {
                            if (!req.cache) {
                                return table.getMany(req);
                            }
                            var cachedResult = getFromTransactionCache(req.keys, req.trans["_cache"], req.cache === "clone");
                            if (cachedResult) {
                                return DexiePromise.resolve(cachedResult);
                            }
                            return table.getMany(req).then(function (res) {
                                req.trans["_cache"] = {
                                    keys: req.keys,
                                    values: req.cache === "clone" ? deepClone(res) : res,
                                };
                                return res;
                            });
                        }, mutate: function (req) {
                            if (req.type !== "add")
                                req.trans["_cache"] = null;
                            return table.mutate(req);
                        } });
                },
            };
        },
    };

    function isCachableContext(ctx, table) {
        return (ctx.trans.mode === 'readonly' &&
            !!ctx.subscr &&
            !ctx.trans.explicit &&
            ctx.trans.db._options.cache !== 'disabled' &&
            !table.schema.primaryKey.outbound);
    }

    function isCachableRequest(type, req) {
        switch (type) {
            case 'query':
                return req.values && !req.unique;
            case 'get':
                return false;
            case 'getMany':
                return false;
            case 'count':
                return false;
            case 'openCursor':
                return false;
        }
    }

    var observabilityMiddleware = {
        stack: "dbcore",
        level: 0,
        name: "Observability",
        create: function (core) {
            var dbName = core.schema.name;
            var FULL_RANGE = new RangeSet(core.MIN_KEY, core.MAX_KEY);
            return __assign(__assign({}, core), { transaction: function (stores, mode, options) {
                    if (PSD.subscr && mode !== 'readonly') {
                        throw new exceptions.ReadOnly("Readwrite transaction in liveQuery context. Querier source: ".concat(PSD.querier));
                    }
                    return core.transaction(stores, mode, options);
                }, table: function (tableName) {
                    var table = core.table(tableName);
                    var schema = table.schema;
                    var primaryKey = schema.primaryKey, indexes = schema.indexes;
                    var extractKey = primaryKey.extractKey, outbound = primaryKey.outbound;
                    var indexesWithAutoIncPK = primaryKey.autoIncrement && indexes.filter(function (index) { return index.compound && index.keyPath.includes(primaryKey.keyPath); });
                    var tableClone = __assign(__assign({}, table), { mutate: function (req) {
                            var _a, _b;
                            var trans = req.trans;
                            var mutatedParts = req.mutatedParts || (req.mutatedParts = {});
                            var getRangeSet = function (indexName) {
                                var part = "idb://".concat(dbName, "/").concat(tableName, "/").concat(indexName);
                                return (mutatedParts[part] ||
                                    (mutatedParts[part] = new RangeSet()));
                            };
                            var pkRangeSet = getRangeSet("");
                            var delsRangeSet = getRangeSet(":dels");
                            var type = req.type;
                            var _c = req.type === "deleteRange"
                                ? [req.range]
                                : req.type === "delete"
                                    ? [req.keys]
                                    : req.values.length < 50
                                        ? [getEffectiveKeys(primaryKey, req).filter(function (id) { return id; }), req.values]
                                        : [], keys = _c[0], newObjs = _c[1];
                            var oldCache = req.trans["_cache"];
                            if (isArray(keys)) {
                                pkRangeSet.addKeys(keys);
                                var oldObjs = type === 'delete' || keys.length === newObjs.length ? getFromTransactionCache(keys, oldCache) : null;
                                if (!oldObjs) {
                                    delsRangeSet.addKeys(keys);
                                }
                                if (oldObjs || newObjs) {
                                    trackAffectedIndexes(getRangeSet, schema, oldObjs, newObjs);
                                }
                            }
                            else if (keys) {
                                var range = {
                                    from: (_a = keys.lower) !== null && _a !== void 0 ? _a : core.MIN_KEY,
                                    to: (_b = keys.upper) !== null && _b !== void 0 ? _b : core.MAX_KEY
                                };
                                delsRangeSet.add(range);
                                pkRangeSet.add(range);
                            }
                            else {
                                pkRangeSet.add(FULL_RANGE);
                                delsRangeSet.add(FULL_RANGE);
                                schema.indexes.forEach(function (idx) { return getRangeSet(idx.name).add(FULL_RANGE); });
                            }
                            return table.mutate(req).then(function (res) {
                                if (keys && (req.type === 'add' || req.type === 'put')) {
                                    pkRangeSet.addKeys(res.results);
                                    if (indexesWithAutoIncPK) {
                                        indexesWithAutoIncPK.forEach(function (idx) {
                                            var idxVals = req.values.map(function (v) { return idx.extractKey(v); });
                                            var pkPos = idx.keyPath.findIndex(function (prop) { return prop === primaryKey.keyPath; });
                                            for (var i = 0, len = res.results.length; i < len; ++i) {
                                                idxVals[i][pkPos] = res.results[i];
                                            }
                                            getRangeSet(idx.name).addKeys(idxVals);
                                        });
                                    }
                                }
                                trans.mutatedParts = extendObservabilitySet(trans.mutatedParts || {}, mutatedParts);
                                return res;
                            });
                        } });
                    var getRange = function (_a) {
                        var _b, _c;
                        var _d = _a.query, index = _d.index, range = _d.range;
                        return [
                            index,
                            new RangeSet((_b = range.lower) !== null && _b !== void 0 ? _b : core.MIN_KEY, (_c = range.upper) !== null && _c !== void 0 ? _c : core.MAX_KEY),
                        ];
                    };
                    var readSubscribers = {
                        get: function (req) { return [primaryKey, new RangeSet(req.key)]; },
                        getMany: function (req) { return [primaryKey, new RangeSet().addKeys(req.keys)]; },
                        count: getRange,
                        query: getRange,
                        openCursor: getRange,
                    };
                    keys(readSubscribers).forEach(function (method) {
                        tableClone[method] = function (req) {
                            var subscr = PSD.subscr;
                            var isLiveQuery = !!subscr;
                            var cachable = isCachableContext(PSD, table) && isCachableRequest(method, req);
                            var obsSet = cachable
                                ? req.obsSet = {}
                                : subscr;
                            if (isLiveQuery) {
                                var getRangeSet = function (indexName) {
                                    var part = "idb://".concat(dbName, "/").concat(tableName, "/").concat(indexName);
                                    return (obsSet[part] ||
                                        (obsSet[part] = new RangeSet()));
                                };
                                var pkRangeSet_1 = getRangeSet("");
                                var delsRangeSet_1 = getRangeSet(":dels");
                                var _a = readSubscribers[method](req), queriedIndex = _a[0], queriedRanges = _a[1];
                                if (method === 'query' && queriedIndex.isPrimaryKey && !req.values) {
                                    delsRangeSet_1.add(queriedRanges);
                                }
                                else {
                                    getRangeSet(queriedIndex.name || "").add(queriedRanges);
                                }
                                if (!queriedIndex.isPrimaryKey) {
                                    if (method === "count") {
                                        delsRangeSet_1.add(FULL_RANGE);
                                    }
                                    else {
                                        var keysPromise_1 = method === "query" &&
                                            outbound &&
                                            req.values &&
                                            table.query(__assign(__assign({}, req), { values: false }));
                                        return table[method].apply(this, arguments).then(function (res) {
                                            if (method === "query") {
                                                if (outbound && req.values) {
                                                    return keysPromise_1.then(function (_a) {
                                                        var resultingKeys = _a.result;
                                                        pkRangeSet_1.addKeys(resultingKeys);
                                                        return res;
                                                    });
                                                }
                                                var pKeys = req.values
                                                    ? res.result.map(extractKey)
                                                    : res.result;
                                                if (req.values) {
                                                    pkRangeSet_1.addKeys(pKeys);
                                                }
                                                else {
                                                    delsRangeSet_1.addKeys(pKeys);
                                                }
                                            }
                                            else if (method === "openCursor") {
                                                var cursor_1 = res;
                                                var wantValues_1 = req.values;
                                                return (cursor_1 &&
                                                    Object.create(cursor_1, {
                                                        key: {
                                                            get: function () {
                                                                delsRangeSet_1.addKey(cursor_1.primaryKey);
                                                                return cursor_1.key;
                                                            },
                                                        },
                                                        primaryKey: {
                                                            get: function () {
                                                                var pkey = cursor_1.primaryKey;
                                                                delsRangeSet_1.addKey(pkey);
                                                                return pkey;
                                                            },
                                                        },
                                                        value: {
                                                            get: function () {
                                                                wantValues_1 && pkRangeSet_1.addKey(cursor_1.primaryKey);
                                                                return cursor_1.value;
                                                            },
                                                        },
                                                    }));
                                            }
                                            return res;
                                        });
                                    }
                                }
                            }
                            return table[method].apply(this, arguments);
                        };
                    });
                    return tableClone;
                } });
        },
    };
    function trackAffectedIndexes(getRangeSet, schema, oldObjs, newObjs) {
        function addAffectedIndex(ix) {
            var rangeSet = getRangeSet(ix.name || "");
            function extractKey(obj) {
                return obj != null ? ix.extractKey(obj) : null;
            }
            var addKeyOrKeys = function (key) { return ix.multiEntry && isArray(key)
                ? key.forEach(function (key) { return rangeSet.addKey(key); })
                : rangeSet.addKey(key); };
            (oldObjs || newObjs).forEach(function (_, i) {
                var oldKey = oldObjs && extractKey(oldObjs[i]);
                var newKey = newObjs && extractKey(newObjs[i]);
                if (cmp(oldKey, newKey) !== 0) {
                    if (oldKey != null)
                        addKeyOrKeys(oldKey);
                    if (newKey != null)
                        addKeyOrKeys(newKey);
                }
            });
        }
        schema.indexes.forEach(addAffectedIndex);
    }

    function adjustOptimisticFromFailures(tblCache, req, res) {
        if (res.numFailures === 0)
            return req;
        if (req.type === 'deleteRange') {
            return null;
        }
        var numBulkOps = req.keys
            ? req.keys.length
            : 'values' in req && req.values
                ? req.values.length
                : 1;
        if (res.numFailures === numBulkOps) {
            return null;
        }
        var clone = __assign({}, req);
        if (isArray(clone.keys)) {
            clone.keys = clone.keys.filter(function (_, i) { return !(i in res.failures); });
        }
        if ('values' in clone && isArray(clone.values)) {
            clone.values = clone.values.filter(function (_, i) { return !(i in res.failures); });
        }
        return clone;
    }

    function isAboveLower(key, range) {
        return range.lower === undefined
            ? true
            : range.lowerOpen
                ? cmp(key, range.lower) > 0
                : cmp(key, range.lower) >= 0;
    }
    function isBelowUpper(key, range) {
        return range.upper === undefined
            ? true
            : range.upperOpen
                ? cmp(key, range.upper) < 0
                : cmp(key, range.upper) <= 0;
    }
    function isWithinRange(key, range) {
        return isAboveLower(key, range) && isBelowUpper(key, range);
    }

    function applyOptimisticOps(result, req, ops, table, cacheEntry, immutable) {
        if (!ops || ops.length === 0)
            return result;
        var index = req.query.index;
        var multiEntry = index.multiEntry;
        var queryRange = req.query.range;
        var primaryKey = table.schema.primaryKey;
        var extractPrimKey = primaryKey.extractKey;
        var extractIndex = index.extractKey;
        var extractLowLevelIndex = (index.lowLevelIndex || index).extractKey;
        var finalResult = ops.reduce(function (result, op) {
            var modifedResult = result;
            var includedValues = [];
            if (op.type === 'add' || op.type === 'put') {
                var includedPKs = new RangeSet();
                for (var i = op.values.length - 1; i >= 0; --i) {
                    var value = op.values[i];
                    var pk = extractPrimKey(value);
                    if (includedPKs.hasKey(pk))
                        continue;
                    var key = extractIndex(value);
                    if (multiEntry && isArray(key)
                        ? key.some(function (k) { return isWithinRange(k, queryRange); })
                        : isWithinRange(key, queryRange)) {
                        includedPKs.addKey(pk);
                        includedValues.push(value);
                    }
                }
            }
            switch (op.type) {
                case 'add': {
                    var existingKeys_1 = new RangeSet().addKeys(req.values ? result.map(function (v) { return extractPrimKey(v); }) : result);
                    modifedResult = result.concat(req.values
                        ? includedValues.filter(function (v) {
                            var key = extractPrimKey(v);
                            if (existingKeys_1.hasKey(key))
                                return false;
                            existingKeys_1.addKey(key);
                            return true;
                        })
                        : includedValues
                            .map(function (v) { return extractPrimKey(v); })
                            .filter(function (k) {
                            if (existingKeys_1.hasKey(k))
                                return false;
                            existingKeys_1.addKey(k);
                            return true;
                        }));
                    break;
                }
                case 'put': {
                    var keySet_1 = new RangeSet().addKeys(op.values.map(function (v) { return extractPrimKey(v); }));
                    modifedResult = result
                        .filter(
                    function (item) { return !keySet_1.hasKey(req.values ? extractPrimKey(item) : item); })
                        .concat(
                    req.values
                        ? includedValues
                        : includedValues.map(function (v) { return extractPrimKey(v); }));
                    break;
                }
                case 'delete':
                    var keysToDelete_1 = new RangeSet().addKeys(op.keys);
                    modifedResult = result.filter(function (item) {
                        return !keysToDelete_1.hasKey(req.values ? extractPrimKey(item) : item);
                    });
                    break;
                case 'deleteRange':
                    var range_1 = op.range;
                    modifedResult = result.filter(function (item) { return !isWithinRange(extractPrimKey(item), range_1); });
                    break;
            }
            return modifedResult;
        }, result);
        if (finalResult === result)
            return result;
        finalResult.sort(function (a, b) {
            return cmp(extractLowLevelIndex(a), extractLowLevelIndex(b)) ||
                cmp(extractPrimKey(a), extractPrimKey(b));
        });
        if (req.limit && req.limit < Infinity) {
            if (finalResult.length > req.limit) {
                finalResult.length = req.limit;
            }
            else if (result.length === req.limit && finalResult.length < req.limit) {
                cacheEntry.dirty = true;
            }
        }
        return immutable ? Object.freeze(finalResult) : finalResult;
    }

    function areRangesEqual(r1, r2) {
        return (cmp(r1.lower, r2.lower) === 0 &&
            cmp(r1.upper, r2.upper) === 0 &&
            !!r1.lowerOpen === !!r2.lowerOpen &&
            !!r1.upperOpen === !!r2.upperOpen);
    }

    function compareLowers(lower1, lower2, lowerOpen1, lowerOpen2) {
        if (lower1 === undefined)
            return lower2 !== undefined ? -1 : 0;
        if (lower2 === undefined)
            return 1;
        var c = cmp(lower1, lower2);
        if (c === 0) {
            if (lowerOpen1 && lowerOpen2)
                return 0;
            if (lowerOpen1)
                return 1;
            if (lowerOpen2)
                return -1;
        }
        return c;
    }
    function compareUppers(upper1, upper2, upperOpen1, upperOpen2) {
        if (upper1 === undefined)
            return upper2 !== undefined ? 1 : 0;
        if (upper2 === undefined)
            return -1;
        var c = cmp(upper1, upper2);
        if (c === 0) {
            if (upperOpen1 && upperOpen2)
                return 0;
            if (upperOpen1)
                return -1;
            if (upperOpen2)
                return 1;
        }
        return c;
    }
    function isSuperRange(r1, r2) {
        return (compareLowers(r1.lower, r2.lower, r1.lowerOpen, r2.lowerOpen) <= 0 &&
            compareUppers(r1.upper, r2.upper, r1.upperOpen, r2.upperOpen) >= 0);
    }

    function findCompatibleQuery(dbName, tableName, type, req) {
        var tblCache = cache["idb://".concat(dbName, "/").concat(tableName)];
        if (!tblCache)
            return [];
        var queries = tblCache.queries[type];
        if (!queries)
            return [null, false, tblCache, null];
        var indexName = req.query ? req.query.index.name : null;
        var entries = queries[indexName || ''];
        if (!entries)
            return [null, false, tblCache, null];
        switch (type) {
            case 'query':
                var equalEntry = entries.find(function (entry) {
                    return entry.req.limit === req.limit &&
                        entry.req.values === req.values &&
                        areRangesEqual(entry.req.query.range, req.query.range);
                });
                if (equalEntry)
                    return [
                        equalEntry,
                        true,
                        tblCache,
                        entries,
                    ];
                var superEntry = entries.find(function (entry) {
                    var limit = 'limit' in entry.req ? entry.req.limit : Infinity;
                    return (limit >= req.limit &&
                        (req.values ? entry.req.values : true) &&
                        isSuperRange(entry.req.query.range, req.query.range));
                });
                return [superEntry, false, tblCache, entries];
            case 'count':
                var countQuery = entries.find(function (entry) {
                    return areRangesEqual(entry.req.query.range, req.query.range);
                });
                return [countQuery, !!countQuery, tblCache, entries];
        }
    }

    function subscribeToCacheEntry(cacheEntry, container, requery, signal) {
        cacheEntry.subscribers.add(requery);
        signal.addEventListener("abort", function () {
            cacheEntry.subscribers.delete(requery);
            if (cacheEntry.subscribers.size === 0) {
                enqueForDeletion(cacheEntry, container);
            }
        });
    }
    function enqueForDeletion(cacheEntry, container) {
        setTimeout(function () {
            if (cacheEntry.subscribers.size === 0) {
                delArrayItem(container, cacheEntry);
            }
        }, 3000);
    }

    var cacheMiddleware = {
        stack: 'dbcore',
        level: 0,
        name: 'Cache',
        create: function (core) {
            var dbName = core.schema.name;
            var coreMW = __assign(__assign({}, core), { transaction: function (stores, mode, options) {
                    var idbtrans = core.transaction(stores, mode, options);
                    if (mode === 'readwrite') {
                        var ac_1 = new AbortController();
                        var signal = ac_1.signal;
                        var endTransaction = function (wasCommitted) { return function () {
                            ac_1.abort();
                            if (mode === 'readwrite') {
                                var affectedSubscribers_1 = new Set();
                                for (var _i = 0, stores_1 = stores; _i < stores_1.length; _i++) {
                                    var storeName = stores_1[_i];
                                    var tblCache = cache["idb://".concat(dbName, "/").concat(storeName)];
                                    if (tblCache) {
                                        var table = core.table(storeName);
                                        var ops = tblCache.optimisticOps.filter(function (op) { return op.trans === idbtrans; });
                                        if (idbtrans._explicit && wasCommitted && idbtrans.mutatedParts) {
                                            for (var _a = 0, _b = Object.values(tblCache.queries.query); _a < _b.length; _a++) {
                                                var entries = _b[_a];
                                                for (var _c = 0, _d = entries.slice(); _c < _d.length; _c++) {
                                                    var entry = _d[_c];
                                                    if (obsSetsOverlap(entry.obsSet, idbtrans.mutatedParts)) {
                                                        delArrayItem(entries, entry);
                                                        entry.subscribers.forEach(function (requery) { return affectedSubscribers_1.add(requery); });
                                                    }
                                                }
                                            }
                                        }
                                        else if (ops.length > 0) {
                                            tblCache.optimisticOps = tblCache.optimisticOps.filter(function (op) { return op.trans !== idbtrans; });
                                            for (var _e = 0, _f = Object.values(tblCache.queries.query); _e < _f.length; _e++) {
                                                var entries = _f[_e];
                                                for (var _g = 0, _h = entries.slice(); _g < _h.length; _g++) {
                                                    var entry = _h[_g];
                                                    if (entry.res != null &&
                                                        idbtrans.mutatedParts
    ) {
                                                        if (wasCommitted && !entry.dirty) {
                                                            var freezeResults = Object.isFrozen(entry.res);
                                                            var modRes = applyOptimisticOps(entry.res, entry.req, ops, table, entry, freezeResults);
                                                            if (entry.dirty) {
                                                                delArrayItem(entries, entry);
                                                                entry.subscribers.forEach(function (requery) { return affectedSubscribers_1.add(requery); });
                                                            }
                                                            else if (modRes !== entry.res) {
                                                                entry.res = modRes;
                                                                entry.promise = DexiePromise.resolve({ result: modRes });
                                                            }
                                                        }
                                                        else {
                                                            if (entry.dirty) {
                                                                delArrayItem(entries, entry);
                                                            }
                                                            entry.subscribers.forEach(function (requery) { return affectedSubscribers_1.add(requery); });
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                affectedSubscribers_1.forEach(function (requery) { return requery(); });
                            }
                        }; };
                        idbtrans.addEventListener('abort', endTransaction(false), {
                            signal: signal,
                        });
                        idbtrans.addEventListener('error', endTransaction(false), {
                            signal: signal,
                        });
                        idbtrans.addEventListener('complete', endTransaction(true), {
                            signal: signal,
                        });
                    }
                    return idbtrans;
                }, table: function (tableName) {
                    var downTable = core.table(tableName);
                    var primKey = downTable.schema.primaryKey;
                    var tableMW = __assign(__assign({}, downTable), { mutate: function (req) {
                            var trans = PSD.trans;
                            if (primKey.outbound ||
                                trans.db._options.cache === 'disabled' ||
                                trans.explicit ||
                                trans.idbtrans.mode !== 'readwrite'
                            ) {
                                return downTable.mutate(req);
                            }
                            var tblCache = cache["idb://".concat(dbName, "/").concat(tableName)];
                            if (!tblCache)
                                return downTable.mutate(req);
                            var promise = downTable.mutate(req);
                            if ((req.type === 'add' || req.type === 'put') && (req.values.length >= 50 || getEffectiveKeys(primKey, req).some(function (key) { return key == null; }))) {
                                promise.then(function (res) {
                                    var reqWithResolvedKeys = __assign(__assign({}, req), { values: req.values.map(function (value, i) {
                                            var _a;
                                            if (res.failures[i])
                                                return value;
                                            var valueWithKey = ((_a = primKey.keyPath) === null || _a === void 0 ? void 0 : _a.includes('.'))
                                                ? deepClone(value)
                                                : __assign({}, value);
                                            setByKeyPath(valueWithKey, primKey.keyPath, res.results[i]);
                                            return valueWithKey;
                                        }) });
                                    var adjustedReq = adjustOptimisticFromFailures(tblCache, reqWithResolvedKeys, res);
                                    tblCache.optimisticOps.push(adjustedReq);
                                    queueMicrotask(function () { return req.mutatedParts && signalSubscribersLazily(req.mutatedParts); });
                                });
                            }
                            else {
                                tblCache.optimisticOps.push(req);
                                req.mutatedParts && signalSubscribersLazily(req.mutatedParts);
                                promise.then(function (res) {
                                    if (res.numFailures > 0) {
                                        delArrayItem(tblCache.optimisticOps, req);
                                        var adjustedReq = adjustOptimisticFromFailures(tblCache, req, res);
                                        if (adjustedReq) {
                                            tblCache.optimisticOps.push(adjustedReq);
                                        }
                                        req.mutatedParts && signalSubscribersLazily(req.mutatedParts);
                                    }
                                });
                                promise.catch(function () {
                                    delArrayItem(tblCache.optimisticOps, req);
                                    req.mutatedParts && signalSubscribersLazily(req.mutatedParts);
                                });
                            }
                            return promise;
                        }, query: function (req) {
                            var _a;
                            if (!isCachableContext(PSD, downTable) || !isCachableRequest("query", req))
                                return downTable.query(req);
                            var freezeResults = ((_a = PSD.trans) === null || _a === void 0 ? void 0 : _a.db._options.cache) === 'immutable';
                            var _b = PSD, requery = _b.requery, signal = _b.signal;
                            var _c = findCompatibleQuery(dbName, tableName, 'query', req), cacheEntry = _c[0], exactMatch = _c[1], tblCache = _c[2], container = _c[3];
                            if (cacheEntry && exactMatch) {
                                cacheEntry.obsSet = req.obsSet;
                            }
                            else {
                                var promise = downTable.query(req).then(function (res) {
                                    var result = res.result;
                                    if (cacheEntry)
                                        cacheEntry.res = result;
                                    if (freezeResults) {
                                        for (var i = 0, l = result.length; i < l; ++i) {
                                            Object.freeze(result[i]);
                                        }
                                        Object.freeze(result);
                                    }
                                    else {
                                        res.result = deepClone(result);
                                    }
                                    return res;
                                }).catch(function (error) {
                                    if (container && cacheEntry)
                                        delArrayItem(container, cacheEntry);
                                    return Promise.reject(error);
                                });
                                cacheEntry = {
                                    obsSet: req.obsSet,
                                    promise: promise,
                                    subscribers: new Set(),
                                    type: 'query',
                                    req: req,
                                    dirty: false,
                                };
                                if (container) {
                                    container.push(cacheEntry);
                                }
                                else {
                                    container = [cacheEntry];
                                    if (!tblCache) {
                                        tblCache = cache["idb://".concat(dbName, "/").concat(tableName)] = {
                                            queries: {
                                                query: {},
                                                count: {},
                                            },
                                            objs: new Map(),
                                            optimisticOps: [],
                                            unsignaledParts: {}
                                        };
                                    }
                                    tblCache.queries.query[req.query.index.name || ''] = container;
                                }
                            }
                            subscribeToCacheEntry(cacheEntry, container, requery, signal);
                            return cacheEntry.promise.then(function (res) {
                                return {
                                    result: applyOptimisticOps(res.result, req, tblCache === null || tblCache === void 0 ? void 0 : tblCache.optimisticOps, downTable, cacheEntry, freezeResults),
                                };
                            });
                        } });
                    return tableMW;
                } });
            return coreMW;
        },
    };

    function vipify(target, vipDb) {
        return new Proxy(target, {
            get: function (target, prop, receiver) {
                if (prop === 'db')
                    return vipDb;
                return Reflect.get(target, prop, receiver);
            }
        });
    }

    var Dexie$1 =  (function () {
        function Dexie(name, options) {
            var _this = this;
            this._middlewares = {};
            this.verno = 0;
            var deps = Dexie.dependencies;
            this._options = options = __assign({
                addons: Dexie.addons, autoOpen: true,
                indexedDB: deps.indexedDB, IDBKeyRange: deps.IDBKeyRange, cache: 'cloned' }, options);
            this._deps = {
                indexedDB: options.indexedDB,
                IDBKeyRange: options.IDBKeyRange
            };
            var addons = options.addons;
            this._dbSchema = {};
            this._versions = [];
            this._storeNames = [];
            this._allTables = {};
            this.idbdb = null;
            this._novip = this;
            var state = {
                dbOpenError: null,
                isBeingOpened: false,
                onReadyBeingFired: null,
                openComplete: false,
                dbReadyResolve: nop,
                dbReadyPromise: null,
                cancelOpen: nop,
                openCanceller: null,
                autoSchema: true,
                PR1398_maxLoop: 3,
                autoOpen: options.autoOpen,
            };
            state.dbReadyPromise = new DexiePromise(function (resolve) {
                state.dbReadyResolve = resolve;
            });
            state.openCanceller = new DexiePromise(function (_, reject) {
                state.cancelOpen = reject;
            });
            this._state = state;
            this.name = name;
            this.on = Events(this, "populate", "blocked", "versionchange", "close", { ready: [promisableChain, nop] });
            this.on.ready.subscribe = override(this.on.ready.subscribe, function (subscribe) {
                return function (subscriber, bSticky) {
                    Dexie.vip(function () {
                        var state = _this._state;
                        if (state.openComplete) {
                            if (!state.dbOpenError)
                                DexiePromise.resolve().then(subscriber);
                            if (bSticky)
                                subscribe(subscriber);
                        }
                        else if (state.onReadyBeingFired) {
                            state.onReadyBeingFired.push(subscriber);
                            if (bSticky)
                                subscribe(subscriber);
                        }
                        else {
                            subscribe(subscriber);
                            var db_1 = _this;
                            if (!bSticky)
                                subscribe(function unsubscribe() {
                                    db_1.on.ready.unsubscribe(subscriber);
                                    db_1.on.ready.unsubscribe(unsubscribe);
                                });
                        }
                    });
                };
            });
            this.Collection = createCollectionConstructor(this);
            this.Table = createTableConstructor(this);
            this.Transaction = createTransactionConstructor(this);
            this.Version = createVersionConstructor(this);
            this.WhereClause = createWhereClauseConstructor(this);
            this.on("versionchange", function (ev) {
                if (ev.newVersion > 0)
                    console.warn("Another connection wants to upgrade database '".concat(_this.name, "'. Closing db now to resume the upgrade."));
                else
                    console.warn("Another connection wants to delete database '".concat(_this.name, "'. Closing db now to resume the delete request."));
                _this.close({ disableAutoOpen: false });
            });
            this.on("blocked", function (ev) {
                if (!ev.newVersion || ev.newVersion < ev.oldVersion)
                    console.warn("Dexie.delete('".concat(_this.name, "') was blocked"));
                else
                    console.warn("Upgrade '".concat(_this.name, "' blocked by other connection holding version ").concat(ev.oldVersion / 10));
            });
            this._maxKey = getMaxKey(options.IDBKeyRange);
            this._createTransaction = function (mode, storeNames, dbschema, parentTransaction) { return new _this.Transaction(mode, storeNames, dbschema, _this._options.chromeTransactionDurability, parentTransaction); };
            this._fireOnBlocked = function (ev) {
                _this.on("blocked").fire(ev);
                connections
                    .filter(function (c) { return c.name === _this.name && c !== _this && !c._state.vcFired; })
                    .map(function (c) { return c.on("versionchange").fire(ev); });
            };
            this.use(cacheExistingValuesMiddleware);
            this.use(cacheMiddleware);
            this.use(observabilityMiddleware);
            this.use(virtualIndexMiddleware);
            this.use(hooksMiddleware);
            var vipDB = new Proxy(this, {
                get: function (_, prop, receiver) {
                    if (prop === '_vip')
                        return true;
                    if (prop === 'table')
                        return function (tableName) { return vipify(_this.table(tableName), vipDB); };
                    var rv = Reflect.get(_, prop, receiver);
                    if (rv instanceof Table)
                        return vipify(rv, vipDB);
                    if (prop === 'tables')
                        return rv.map(function (t) { return vipify(t, vipDB); });
                    if (prop === '_createTransaction')
                        return function () {
                            var tx = rv.apply(this, arguments);
                            return vipify(tx, vipDB);
                        };
                    return rv;
                }
            });
            this.vip = vipDB;
            addons.forEach(function (addon) { return addon(_this); });
        }
        Dexie.prototype.version = function (versionNumber) {
            if (isNaN(versionNumber) || versionNumber < 0.1)
                throw new exceptions.Type("Given version is not a positive number");
            versionNumber = Math.round(versionNumber * 10) / 10;
            if (this.idbdb || this._state.isBeingOpened)
                throw new exceptions.Schema("Cannot add version when database is open");
            this.verno = Math.max(this.verno, versionNumber);
            var versions = this._versions;
            var versionInstance = versions.filter(function (v) { return v._cfg.version === versionNumber; })[0];
            if (versionInstance)
                return versionInstance;
            versionInstance = new this.Version(versionNumber);
            versions.push(versionInstance);
            versions.sort(lowerVersionFirst);
            versionInstance.stores({});
            this._state.autoSchema = false;
            return versionInstance;
        };
        Dexie.prototype._whenReady = function (fn) {
            var _this = this;
            return (this.idbdb && (this._state.openComplete || PSD.letThrough || this._vip)) ? fn() : new DexiePromise(function (resolve, reject) {
                if (_this._state.openComplete) {
                    return reject(new exceptions.DatabaseClosed(_this._state.dbOpenError));
                }
                if (!_this._state.isBeingOpened) {
                    if (!_this._state.autoOpen) {
                        reject(new exceptions.DatabaseClosed());
                        return;
                    }
                    _this.open().catch(nop);
                }
                _this._state.dbReadyPromise.then(resolve, reject);
            }).then(fn);
        };
        Dexie.prototype.use = function (_a) {
            var stack = _a.stack, create = _a.create, level = _a.level, name = _a.name;
            if (name)
                this.unuse({ stack: stack, name: name });
            var middlewares = this._middlewares[stack] || (this._middlewares[stack] = []);
            middlewares.push({ stack: stack, create: create, level: level == null ? 10 : level, name: name });
            middlewares.sort(function (a, b) { return a.level - b.level; });
            return this;
        };
        Dexie.prototype.unuse = function (_a) {
            var stack = _a.stack, name = _a.name, create = _a.create;
            if (stack && this._middlewares[stack]) {
                this._middlewares[stack] = this._middlewares[stack].filter(function (mw) {
                    return create ? mw.create !== create :
                        name ? mw.name !== name :
                            false;
                });
            }
            return this;
        };
        Dexie.prototype.open = function () {
            var _this = this;
            return usePSD(globalPSD,
            function () { return dexieOpen(_this); });
        };
        Dexie.prototype._close = function () {
            var state = this._state;
            var idx = connections.indexOf(this);
            if (idx >= 0)
                connections.splice(idx, 1);
            if (this.idbdb) {
                try {
                    this.idbdb.close();
                }
                catch (e) { }
                this.idbdb = null;
            }
            if (!state.isBeingOpened) {
                state.dbReadyPromise = new DexiePromise(function (resolve) {
                    state.dbReadyResolve = resolve;
                });
                state.openCanceller = new DexiePromise(function (_, reject) {
                    state.cancelOpen = reject;
                });
            }
        };
        Dexie.prototype.close = function (_a) {
            var _b = _a === void 0 ? { disableAutoOpen: true } : _a, disableAutoOpen = _b.disableAutoOpen;
            var state = this._state;
            if (disableAutoOpen) {
                if (state.isBeingOpened) {
                    state.cancelOpen(new exceptions.DatabaseClosed());
                }
                this._close();
                state.autoOpen = false;
                state.dbOpenError = new exceptions.DatabaseClosed();
            }
            else {
                this._close();
                state.autoOpen = this._options.autoOpen ||
                    state.isBeingOpened;
                state.openComplete = false;
                state.dbOpenError = null;
            }
        };
        Dexie.prototype.delete = function (closeOptions) {
            var _this = this;
            if (closeOptions === void 0) { closeOptions = { disableAutoOpen: true }; }
            var hasInvalidArguments = arguments.length > 0 && typeof arguments[0] !== 'object';
            var state = this._state;
            return new DexiePromise(function (resolve, reject) {
                var doDelete = function () {
                    _this.close(closeOptions);
                    var req = _this._deps.indexedDB.deleteDatabase(_this.name);
                    req.onsuccess = wrap(function () {
                        _onDatabaseDeleted(_this._deps, _this.name);
                        resolve();
                    });
                    req.onerror = eventRejectHandler(reject);
                    req.onblocked = _this._fireOnBlocked;
                };
                if (hasInvalidArguments)
                    throw new exceptions.InvalidArgument("Invalid closeOptions argument to db.delete()");
                if (state.isBeingOpened) {
                    state.dbReadyPromise.then(doDelete);
                }
                else {
                    doDelete();
                }
            });
        };
        Dexie.prototype.backendDB = function () {
            return this.idbdb;
        };
        Dexie.prototype.isOpen = function () {
            return this.idbdb !== null;
        };
        Dexie.prototype.hasBeenClosed = function () {
            var dbOpenError = this._state.dbOpenError;
            return dbOpenError && (dbOpenError.name === 'DatabaseClosed');
        };
        Dexie.prototype.hasFailed = function () {
            return this._state.dbOpenError !== null;
        };
        Dexie.prototype.dynamicallyOpened = function () {
            return this._state.autoSchema;
        };
        Object.defineProperty(Dexie.prototype, "tables", {
            get: function () {
                var _this = this;
                return keys(this._allTables).map(function (name) { return _this._allTables[name]; });
            },
            enumerable: false,
            configurable: true
        });
        Dexie.prototype.transaction = function () {
            var args = extractTransactionArgs.apply(this, arguments);
            return this._transaction.apply(this, args);
        };
        Dexie.prototype._transaction = function (mode, tables, scopeFunc) {
            var _this = this;
            var parentTransaction = PSD.trans;
            if (!parentTransaction || parentTransaction.db !== this || mode.indexOf('!') !== -1)
                parentTransaction = null;
            var onlyIfCompatible = mode.indexOf('?') !== -1;
            mode = mode.replace('!', '').replace('?', '');
            var idbMode, storeNames;
            try {
                storeNames = tables.map(function (table) {
                    var storeName = table instanceof _this.Table ? table.name : table;
                    if (typeof storeName !== 'string')
                        throw new TypeError("Invalid table argument to Dexie.transaction(). Only Table or String are allowed");
                    return storeName;
                });
                if (mode == "r" || mode === READONLY)
                    idbMode = READONLY;
                else if (mode == "rw" || mode == READWRITE)
                    idbMode = READWRITE;
                else
                    throw new exceptions.InvalidArgument("Invalid transaction mode: " + mode);
                if (parentTransaction) {
                    if (parentTransaction.mode === READONLY && idbMode === READWRITE) {
                        if (onlyIfCompatible) {
                            parentTransaction = null;
                        }
                        else
                            throw new exceptions.SubTransaction("Cannot enter a sub-transaction with READWRITE mode when parent transaction is READONLY");
                    }
                    if (parentTransaction) {
                        storeNames.forEach(function (storeName) {
                            if (parentTransaction && parentTransaction.storeNames.indexOf(storeName) === -1) {
                                if (onlyIfCompatible) {
                                    parentTransaction = null;
                                }
                                else
                                    throw new exceptions.SubTransaction("Table " + storeName +
                                        " not included in parent transaction.");
                            }
                        });
                    }
                    if (onlyIfCompatible && parentTransaction && !parentTransaction.active) {
                        parentTransaction = null;
                    }
                }
            }
            catch (e) {
                return parentTransaction ?
                    parentTransaction._promise(null, function (_, reject) { reject(e); }) :
                    rejection(e);
            }
            var enterTransaction = enterTransactionScope.bind(null, this, idbMode, storeNames, parentTransaction, scopeFunc);
            return (parentTransaction ?
                parentTransaction._promise(idbMode, enterTransaction, "lock") :
                PSD.trans ?
                    usePSD(PSD.transless, function () { return _this._whenReady(enterTransaction); }) :
                    this._whenReady(enterTransaction));
        };
        Dexie.prototype.table = function (tableName) {
            if (!hasOwn(this._allTables, tableName)) {
                throw new exceptions.InvalidTable("Table ".concat(tableName, " does not exist"));
            }
            return this._allTables[tableName];
        };
        return Dexie;
    }());

    var symbolObservable = typeof Symbol !== "undefined" && "observable" in Symbol
        ? Symbol.observable
        : "@@observable";
    var Observable =  (function () {
        function Observable(subscribe) {
            this._subscribe = subscribe;
        }
        Observable.prototype.subscribe = function (x, error, complete) {
            return this._subscribe(!x || typeof x === "function" ? { next: x, error: error, complete: complete } : x);
        };
        Observable.prototype[symbolObservable] = function () {
            return this;
        };
        return Observable;
    }());

    var domDeps;
    try {
        domDeps = {
            indexedDB: _global.indexedDB || _global.mozIndexedDB || _global.webkitIndexedDB || _global.msIndexedDB,
            IDBKeyRange: _global.IDBKeyRange || _global.webkitIDBKeyRange
        };
    }
    catch (e) {
        domDeps = { indexedDB: null, IDBKeyRange: null };
    }

    function liveQuery(querier) {
        var hasValue = false;
        var currentValue;
        var observable = new Observable(function (observer) {
            var scopeFuncIsAsync = isAsyncFunction(querier);
            function execute(ctx) {
                var wasRootExec = beginMicroTickScope();
                try {
                    if (scopeFuncIsAsync) {
                        incrementExpectedAwaits();
                    }
                    var rv = newScope(querier, ctx);
                    if (scopeFuncIsAsync) {
                        rv = rv.finally(decrementExpectedAwaits);
                    }
                    return rv;
                }
                finally {
                    wasRootExec && endMicroTickScope();
                }
            }
            var closed = false;
            var abortController;
            var accumMuts = {};
            var currentObs = {};
            var subscription = {
                get closed() {
                    return closed;
                },
                unsubscribe: function () {
                    if (closed)
                        return;
                    closed = true;
                    if (abortController)
                        abortController.abort();
                    if (startedListening)
                        globalEvents.storagemutated.unsubscribe(mutationListener);
                },
            };
            observer.start && observer.start(subscription);
            var startedListening = false;
            var doQuery = function () { return execInGlobalContext(_doQuery); };
            function shouldNotify() {
                return obsSetsOverlap(currentObs, accumMuts);
            }
            var mutationListener = function (parts) {
                extendObservabilitySet(accumMuts, parts);
                if (shouldNotify()) {
                    doQuery();
                }
            };
            var _doQuery = function () {
                if (closed ||
                    !domDeps.indexedDB)
                 {
                    return;
                }
                accumMuts = {};
                var subscr = {};
                if (abortController)
                    abortController.abort();
                abortController = new AbortController();
                var ctx = {
                    subscr: subscr,
                    signal: abortController.signal,
                    requery: doQuery,
                    querier: querier,
                    trans: null
                };
                var ret = execute(ctx);
                Promise.resolve(ret).then(function (result) {
                    hasValue = true;
                    currentValue = result;
                    if (closed || ctx.signal.aborted) {
                        return;
                    }
                    accumMuts = {};
                    currentObs = subscr;
                    if (!objectIsEmpty(currentObs) && !startedListening) {
                        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, mutationListener);
                        startedListening = true;
                    }
                    execInGlobalContext(function () { return !closed && observer.next && observer.next(result); });
                }, function (err) {
                    hasValue = false;
                    if (!['DatabaseClosedError', 'AbortError'].includes(err === null || err === void 0 ? void 0 : err.name)) {
                        if (!closed)
                            execInGlobalContext(function () {
                                if (closed)
                                    return;
                                observer.error && observer.error(err);
                            });
                    }
                });
            };
            setTimeout(doQuery, 0);
            return subscription;
        });
        observable.hasValue = function () { return hasValue; };
        observable.getValue = function () { return currentValue; };
        return observable;
    }

    var Dexie = Dexie$1;
    props(Dexie, __assign(__assign({}, fullNameExceptions), {
        delete: function (databaseName) {
            var db = new Dexie(databaseName, { addons: [] });
            return db.delete();
        },
        exists: function (name) {
            return new Dexie(name, { addons: [] }).open().then(function (db) {
                db.close();
                return true;
            }).catch('NoSuchDatabaseError', function () { return false; });
        },
        getDatabaseNames: function (cb) {
            try {
                return getDatabaseNames(Dexie.dependencies).then(cb);
            }
            catch (_a) {
                return rejection(new exceptions.MissingAPI());
            }
        },
        defineClass: function () {
            function Class(content) {
                extend(this, content);
            }
            return Class;
        }, ignoreTransaction: function (scopeFunc) {
            return PSD.trans ?
                usePSD(PSD.transless, scopeFunc) :
                scopeFunc();
        }, vip: vip, async: function (generatorFn) {
            return function () {
                try {
                    var rv = awaitIterator(generatorFn.apply(this, arguments));
                    if (!rv || typeof rv.then !== 'function')
                        return DexiePromise.resolve(rv);
                    return rv;
                }
                catch (e) {
                    return rejection(e);
                }
            };
        }, spawn: function (generatorFn, args, thiz) {
            try {
                var rv = awaitIterator(generatorFn.apply(thiz, args || []));
                if (!rv || typeof rv.then !== 'function')
                    return DexiePromise.resolve(rv);
                return rv;
            }
            catch (e) {
                return rejection(e);
            }
        },
        currentTransaction: {
            get: function () { return PSD.trans || null; }
        }, waitFor: function (promiseOrFunction, optionalTimeout) {
            var promise = DexiePromise.resolve(typeof promiseOrFunction === 'function' ?
                Dexie.ignoreTransaction(promiseOrFunction) :
                promiseOrFunction)
                .timeout(optionalTimeout || 60000);
            return PSD.trans ?
                PSD.trans.waitFor(promise) :
                promise;
        },
        Promise: DexiePromise,
        debug: {
            get: function () { return debug; },
            set: function (value) {
                setDebug(value);
            }
        },
        derive: derive, extend: extend, props: props, override: override,
        Events: Events, on: globalEvents, liveQuery: liveQuery, extendObservabilitySet: extendObservabilitySet,
        getByKeyPath: getByKeyPath, setByKeyPath: setByKeyPath, delByKeyPath: delByKeyPath, shallowClone: shallowClone, deepClone: deepClone, getObjectDiff: getObjectDiff, cmp: cmp, asap: asap$1,
        minKey: minKey,
        addons: [],
        connections: connections,
        errnames: errnames,
        dependencies: domDeps, cache: cache,
        semVer: DEXIE_VERSION, version: DEXIE_VERSION.split('.')
            .map(function (n) { return parseInt(n); })
            .reduce(function (p, c, i) { return p + (c / Math.pow(10, i * 2)); }) }));
    Dexie.maxKey = getMaxKey(Dexie.dependencies.IDBKeyRange);

    if (typeof dispatchEvent !== 'undefined' && typeof addEventListener !== 'undefined') {
        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, function (updatedParts) {
            if (!propagatingLocally) {
                var event_1;
                event_1 = new CustomEvent(STORAGE_MUTATED_DOM_EVENT_NAME, {
                    detail: updatedParts
                });
                propagatingLocally = true;
                dispatchEvent(event_1);
                propagatingLocally = false;
            }
        });
        addEventListener(STORAGE_MUTATED_DOM_EVENT_NAME, function (_a) {
            var detail = _a.detail;
            if (!propagatingLocally) {
                propagateLocally(detail);
            }
        });
    }
    function propagateLocally(updateParts) {
        var wasMe = propagatingLocally;
        try {
            propagatingLocally = true;
            globalEvents.storagemutated.fire(updateParts);
            signalSubscribersNow(updateParts, true);
        }
        finally {
            propagatingLocally = wasMe;
        }
    }
    var propagatingLocally = false;

    var bc;
    var createBC = function () { };
    if (typeof BroadcastChannel !== 'undefined') {
        createBC = function () {
            bc = new BroadcastChannel(STORAGE_MUTATED_DOM_EVENT_NAME);
            bc.onmessage = function (ev) { return ev.data && propagateLocally(ev.data); };
        };
        createBC();
        if (typeof bc.unref === 'function') {
            bc.unref();
        }
        globalEvents(DEXIE_STORAGE_MUTATED_EVENT_NAME, function (changedParts) {
            if (!propagatingLocally) {
                bc.postMessage(changedParts);
            }
        });
    }

    if (typeof addEventListener !== 'undefined') {
        addEventListener('pagehide', function (event) {
            if (!Dexie$1.disableBfCache && event.persisted) {
                if (debug)
                    console.debug('Dexie: handling persisted pagehide');
                bc === null || bc === void 0 ? void 0 : bc.close();
                for (var _i = 0, connections_1 = connections; _i < connections_1.length; _i++) {
                    var db = connections_1[_i];
                    db.close({ disableAutoOpen: false });
                }
            }
        });
        addEventListener('pageshow', function (event) {
            if (!Dexie$1.disableBfCache && event.persisted) {
                if (debug)
                    console.debug('Dexie: handling persisted pageshow');
                createBC();
                propagateLocally({ all: new RangeSet(-Infinity, [[]]) });
            }
        });
    }

    function add(value) {
        return new PropModification({ add: value });
    }

    function remove(value) {
        return new PropModification({ remove: value });
    }

    function replacePrefix(a, b) {
        return new PropModification({ replacePrefix: [a, b] });
    }

    DexiePromise.rejectionMapper = mapError;
    setDebug(debug);

    var namedExports = /*#__PURE__*/Object.freeze({
        __proto__: null,
        Dexie: Dexie$1,
        liveQuery: liveQuery,
        Entity: Entity,
        cmp: cmp,
        PropModification: PropModification,
        replacePrefix: replacePrefix,
        add: add,
        remove: remove,
        'default': Dexie$1,
        RangeSet: RangeSet,
        mergeRanges: mergeRanges,
        rangesOverlap: rangesOverlap
    });

    __assign(Dexie$1, namedExports, { default: Dexie$1 });

    return Dexie$1;

}));


}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate)

},{"timers":225}],207:[function(require,module,exports){
/**
 * EvEmitter v1.1.0
 * Lil' event emitter
 * MIT License
 */

/* jshint unused: true, undef: true, strict: true */

( function( global, factory ) {
  // universal module definition
  /* jshint strict: false */ /* globals define, module, window */
  if ( typeof define == 'function' && define.amd ) {
    // AMD - RequireJS
    define( factory );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS - Browserify, Webpack
    module.exports = factory();
  } else {
    // Browser globals
    global.EvEmitter = factory();
  }

}( typeof window != 'undefined' ? window : this, function() {

"use strict";

function EvEmitter() {}

var proto = EvEmitter.prototype;

proto.on = function( eventName, listener ) {
  if ( !eventName || !listener ) {
    return;
  }
  // set events hash
  var events = this._events = this._events || {};
  // set listeners array
  var listeners = events[ eventName ] = events[ eventName ] || [];
  // only add once
  if ( listeners.indexOf( listener ) == -1 ) {
    listeners.push( listener );
  }

  return this;
};

proto.once = function( eventName, listener ) {
  if ( !eventName || !listener ) {
    return;
  }
  // add event
  this.on( eventName, listener );
  // set once flag
  // set onceEvents hash
  var onceEvents = this._onceEvents = this._onceEvents || {};
  // set onceListeners object
  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
  // set flag
  onceListeners[ listener ] = true;

  return this;
};

proto.off = function( eventName, listener ) {
  var listeners = this._events && this._events[ eventName ];
  if ( !listeners || !listeners.length ) {
    return;
  }
  var index = listeners.indexOf( listener );
  if ( index != -1 ) {
    listeners.splice( index, 1 );
  }

  return this;
};

proto.emitEvent = function( eventName, args ) {
  var listeners = this._events && this._events[ eventName ];
  if ( !listeners || !listeners.length ) {
    return;
  }
  // copy over to avoid interference if .off() in listener
  listeners = listeners.slice(0);
  args = args || [];
  // once stuff
  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];

  for ( var i=0; i < listeners.length; i++ ) {
    var listener = listeners[i]
    var isOnce = onceListeners && onceListeners[ listener ];
    if ( isOnce ) {
      // remove listener
      // remove before trigger to prevent recursion
      this.off( eventName, listener );
      // unset once flag
      delete onceListeners[ listener ];
    }
    // trigger listener
    listener.apply( this, args );
  }

  return this;
};

proto.allOff = function() {
  delete this._events;
  delete this._onceEvents;
};

return EvEmitter;

}));

},{}],208:[function(require,module,exports){
/**
 * Fizzy UI utils v2.0.7
 * MIT license
 */

/*jshint browser: true, undef: true, unused: true, strict: true */

( function( window, factory ) {
  // universal module definition
  /*jshint strict: false */ /*globals define, module, require */

  if ( typeof define == 'function' && define.amd ) {
    // AMD
    define( [
      'desandro-matches-selector/matches-selector'
    ], function( matchesSelector ) {
      return factory( window, matchesSelector );
    });
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS
    module.exports = factory(
      window,
      require('desandro-matches-selector')
    );
  } else {
    // browser global
    window.fizzyUIUtils = factory(
      window,
      window.matchesSelector
    );
  }

}( window, function factory( window, matchesSelector ) {

'use strict';

var utils = {};

// ----- extend ----- //

// extends objects
utils.extend = function( a, b ) {
  for ( var prop in b ) {
    a[ prop ] = b[ prop ];
  }
  return a;
};

// ----- modulo ----- //

utils.modulo = function( num, div ) {
  return ( ( num % div ) + div ) % div;
};

// ----- makeArray ----- //

var arraySlice = Array.prototype.slice;

// turn element or nodeList into an array
utils.makeArray = function( obj ) {
  if ( Array.isArray( obj ) ) {
    // use object if already an array
    return obj;
  }
  // return empty array if undefined or null. #6
  if ( obj === null || obj === undefined ) {
    return [];
  }

  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
  if ( isArrayLike ) {
    // convert nodeList to array
    return arraySlice.call( obj );
  }

  // array of single index
  return [ obj ];
};

// ----- removeFrom ----- //

utils.removeFrom = function( ary, obj ) {
  var index = ary.indexOf( obj );
  if ( index != -1 ) {
    ary.splice( index, 1 );
  }
};

// ----- getParent ----- //

utils.getParent = function( elem, selector ) {
  while ( elem.parentNode && elem != document.body ) {
    elem = elem.parentNode;
    if ( matchesSelector( elem, selector ) ) {
      return elem;
    }
  }
};

// ----- getQueryElement ----- //

// use element as selector string
utils.getQueryElement = function( elem ) {
  if ( typeof elem == 'string' ) {
    return document.querySelector( elem );
  }
  return elem;
};

// ----- handleEvent ----- //

// enable .ontype to trigger from .addEventListener( elem, 'type' )
utils.handleEvent = function( event ) {
  var method = 'on' + event.type;
  if ( this[ method ] ) {
    this[ method ]( event );
  }
};

// ----- filterFindElements ----- //

utils.filterFindElements = function( elems, selector ) {
  // make array of elems
  elems = utils.makeArray( elems );
  var ffElems = [];

  elems.forEach( function( elem ) {
    // check that elem is an actual element
    if ( !( elem instanceof HTMLElement ) ) {
      return;
    }
    // add elem if no selector
    if ( !selector ) {
      ffElems.push( elem );
      return;
    }
    // filter & find items if we have a selector
    // filter
    if ( matchesSelector( elem, selector ) ) {
      ffElems.push( elem );
    }
    // find children
    var childElems = elem.querySelectorAll( selector );
    // concat childElems to filterFound array
    for ( var i=0; i < childElems.length; i++ ) {
      ffElems.push( childElems[i] );
    }
  });

  return ffElems;
};

// ----- debounceMethod ----- //

utils.debounceMethod = function( _class, methodName, threshold ) {
  threshold = threshold || 100;
  // original method
  var method = _class.prototype[ methodName ];
  var timeoutName = methodName + 'Timeout';

  _class.prototype[ methodName ] = function() {
    var timeout = this[ timeoutName ];
    clearTimeout( timeout );

    var args = arguments;
    var _this = this;
    this[ timeoutName ] = setTimeout( function() {
      method.apply( _this, args );
      delete _this[ timeoutName ];
    }, threshold );
  };
};

// ----- docReady ----- //

utils.docReady = function( callback ) {
  var readyState = document.readyState;
  if ( readyState == 'complete' || readyState == 'interactive' ) {
    // do async to allow for other scripts to run. metafizzy/flickity#441
    setTimeout( callback );
  } else {
    document.addEventListener( 'DOMContentLoaded', callback );
  }
};

// ----- htmlInit ----- //

// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
utils.toDashed = function( str ) {
  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
    return $1 + '-' + $2;
  }).toLowerCase();
};

var console = window.console;
/**
 * allow user to initialize classes via [data-namespace] or .js-namespace class
 * htmlInit( Widget, 'widgetName' )
 * options are parsed from data-namespace-options
 */
utils.htmlInit = function( WidgetClass, namespace ) {
  utils.docReady( function() {
    var dashedNamespace = utils.toDashed( namespace );
    var dataAttr = 'data-' + dashedNamespace;
    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
    var elems = utils.makeArray( dataAttrElems )
      .concat( utils.makeArray( jsDashElems ) );
    var dataOptionsAttr = dataAttr + '-options';
    var jQuery = window.jQuery;

    elems.forEach( function( elem ) {
      var attr = elem.getAttribute( dataAttr ) ||
        elem.getAttribute( dataOptionsAttr );
      var options;
      try {
        options = attr && JSON.parse( attr );
      } catch ( error ) {
        // log error, do not initialize
        if ( console ) {
          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
          ': ' + error );
        }
        return;
      }
      // initialize
      var instance = new WidgetClass( elem, options );
      // make available via $().data('namespace')
      if ( jQuery ) {
        jQuery.data( elem, namespace, instance );
      }
    });

  });
};

// -----  ----- //

return utils;

}));

},{"desandro-matches-selector":205}],209:[function(require,module,exports){
/*!
 * getSize v2.0.3
 * measure size of elements
 * MIT license
 */

/* jshint browser: true, strict: true, undef: true, unused: true */
/* globals console: false */

( function( window, factory ) {
  /* jshint strict: false */ /* globals define, module */
  if ( typeof define == 'function' && define.amd ) {
    // AMD
    define( factory );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS
    module.exports = factory();
  } else {
    // browser global
    window.getSize = factory();
  }

})( window, function factory() {
'use strict';

// -------------------------- helpers -------------------------- //

// get a number from a string, not a percentage
function getStyleSize( value ) {
  var num = parseFloat( value );
  // not a percent like '100%', and a number
  var isValid = value.indexOf('%') == -1 && !isNaN( num );
  return isValid && num;
}

function noop() {}

var logError = typeof console == 'undefined' ? noop :
  function( message ) {
    console.error( message );
  };

// -------------------------- measurements -------------------------- //

var measurements = [
  'paddingLeft',
  'paddingRight',
  'paddingTop',
  'paddingBottom',
  'marginLeft',
  'marginRight',
  'marginTop',
  'marginBottom',
  'borderLeftWidth',
  'borderRightWidth',
  'borderTopWidth',
  'borderBottomWidth'
];

var measurementsLength = measurements.length;

function getZeroSize() {
  var size = {
    width: 0,
    height: 0,
    innerWidth: 0,
    innerHeight: 0,
    outerWidth: 0,
    outerHeight: 0
  };
  for ( var i=0; i < measurementsLength; i++ ) {
    var measurement = measurements[i];
    size[ measurement ] = 0;
  }
  return size;
}

// -------------------------- getStyle -------------------------- //

/**
 * getStyle, get style of element, check for Firefox bug
 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
 */
function getStyle( elem ) {
  var style = getComputedStyle( elem );
  if ( !style ) {
    logError( 'Style returned ' + style +
      '. Are you running this code in a hidden iframe on Firefox? ' +
      'See https://bit.ly/getsizebug1' );
  }
  return style;
}

// -------------------------- setup -------------------------- //

var isSetup = false;

var isBoxSizeOuter;

/**
 * setup
 * check isBoxSizerOuter
 * do on first getSize() rather than on page load for Firefox bug
 */
function setup() {
  // setup once
  if ( isSetup ) {
    return;
  }
  isSetup = true;

  // -------------------------- box sizing -------------------------- //

  /**
   * Chrome & Safari measure the outer-width on style.width on border-box elems
   * IE11 & Firefox<29 measures the inner-width
   */
  var div = document.createElement('div');
  div.style.width = '200px';
  div.style.padding = '1px 2px 3px 4px';
  div.style.borderStyle = 'solid';
  div.style.borderWidth = '1px 2px 3px 4px';
  div.style.boxSizing = 'border-box';

  var body = document.body || document.documentElement;
  body.appendChild( div );
  var style = getStyle( div );
  // round value for browser zoom. desandro/masonry#928
  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
  getSize.isBoxSizeOuter = isBoxSizeOuter;

  body.removeChild( div );
}

// -------------------------- getSize -------------------------- //

function getSize( elem ) {
  setup();

  // use querySeletor if elem is string
  if ( typeof elem == 'string' ) {
    elem = document.querySelector( elem );
  }

  // do not proceed on non-objects
  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
    return;
  }

  var style = getStyle( elem );

  // if hidden, everything is 0
  if ( style.display == 'none' ) {
    return getZeroSize();
  }

  var size = {};
  size.width = elem.offsetWidth;
  size.height = elem.offsetHeight;

  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';

  // get all measurements
  for ( var i=0; i < measurementsLength; i++ ) {
    var measurement = measurements[i];
    var value = style[ measurement ];
    var num = parseFloat( value );
    // any 'auto', 'medium' value will be 0
    size[ measurement ] = !isNaN( num ) ? num : 0;
  }

  var paddingWidth = size.paddingLeft + size.paddingRight;
  var paddingHeight = size.paddingTop + size.paddingBottom;
  var marginWidth = size.marginLeft + size.marginRight;
  var marginHeight = size.marginTop + size.marginBottom;
  var borderWidth = size.borderLeftWidth + size.borderRightWidth;
  var borderHeight = size.borderTopWidth + size.borderBottomWidth;

  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;

  // overwrite width and height if we can get it from style
  var styleWidth = getStyleSize( style.width );
  if ( styleWidth !== false ) {
    size.width = styleWidth +
      // add padding and border unless it's already including it
      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
  }

  var styleHeight = getStyleSize( style.height );
  if ( styleHeight !== false ) {
    size.height = styleHeight +
      // add padding and border unless it's already including it
      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
  }

  size.innerWidth = size.width - ( paddingWidth + borderWidth );
  size.innerHeight = size.height - ( paddingHeight + borderHeight );

  size.outerWidth = size.width + marginWidth;
  size.outerHeight = size.height + marginHeight;

  return size;
}

return getSize;

});

},{}],210:[function(require,module,exports){
/**
 * Check if argument is a HTML element.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.node = function(value) {
    return value !== undefined
        && value instanceof HTMLElement
        && value.nodeType === 1;
};

/**
 * Check if argument is a list of HTML elements.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.nodeList = function(value) {
    var type = Object.prototype.toString.call(value);

    return value !== undefined
        && (type === '[object NodeList]' || type === '[object HTMLCollection]')
        && ('length' in value)
        && (value.length === 0 || exports.node(value[0]));
};

/**
 * Check if argument is a string.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.string = function(value) {
    return typeof value === 'string'
        || value instanceof String;
};

/**
 * Check if argument is a function.
 *
 * @param {Object} value
 * @return {Boolean}
 */
exports.fn = function(value) {
    var type = Object.prototype.toString.call(value);

    return type === '[object Function]';
};

},{}],211:[function(require,module,exports){
var is = require('./is');
var delegate = require('delegate');

/**
 * Validates all params and calls the right
 * listener function based on its target type.
 *
 * @param {String|HTMLElement|HTMLCollection|NodeList} target
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listen(target, type, callback) {
    if (!target && !type && !callback) {
        throw new Error('Missing required arguments');
    }

    if (!is.string(type)) {
        throw new TypeError('Second argument must be a String');
    }

    if (!is.fn(callback)) {
        throw new TypeError('Third argument must be a Function');
    }

    if (is.node(target)) {
        return listenNode(target, type, callback);
    }
    else if (is.nodeList(target)) {
        return listenNodeList(target, type, callback);
    }
    else if (is.string(target)) {
        return listenSelector(target, type, callback);
    }
    else {
        throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');
    }
}

/**
 * Adds an event listener to a HTML element
 * and returns a remove listener function.
 *
 * @param {HTMLElement} node
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenNode(node, type, callback) {
    node.addEventListener(type, callback);

    return {
        destroy: function() {
            node.removeEventListener(type, callback);
        }
    }
}

/**
 * Add an event listener to a list of HTML elements
 * and returns a remove listener function.
 *
 * @param {NodeList|HTMLCollection} nodeList
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenNodeList(nodeList, type, callback) {
    Array.prototype.forEach.call(nodeList, function(node) {
        node.addEventListener(type, callback);
    });

    return {
        destroy: function() {
            Array.prototype.forEach.call(nodeList, function(node) {
                node.removeEventListener(type, callback);
            });
        }
    }
}

/**
 * Add an event listener to a selector
 * and returns a remove listener function.
 *
 * @param {String} selector
 * @param {String} type
 * @param {Function} callback
 * @return {Object}
 */
function listenSelector(selector, type, callback) {
    return delegate(document.body, selector, type, callback);
}

module.exports = listen;

},{"./is":210,"delegate":204}],212:[function(require,module,exports){
/*!
 * imagesLoaded v4.1.4
 * JavaScript is all like "You images are done yet or what?"
 * MIT License
 */

( function( window, factory ) { 'use strict';
  // universal module definition

  /*global define: false, module: false, require: false */

  if ( typeof define == 'function' && define.amd ) {
    // AMD
    define( [
      'ev-emitter/ev-emitter'
    ], function( EvEmitter ) {
      return factory( window, EvEmitter );
    });
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS
    module.exports = factory(
      window,
      require('ev-emitter')
    );
  } else {
    // browser global
    window.imagesLoaded = factory(
      window,
      window.EvEmitter
    );
  }

})( typeof window !== 'undefined' ? window : this,

// --------------------------  factory -------------------------- //

function factory( window, EvEmitter ) {

'use strict';

var $ = window.jQuery;
var console = window.console;

// -------------------------- helpers -------------------------- //

// extend objects
function extend( a, b ) {
  for ( var prop in b ) {
    a[ prop ] = b[ prop ];
  }
  return a;
}

var arraySlice = Array.prototype.slice;

// turn element or nodeList into an array
function makeArray( obj ) {
  if ( Array.isArray( obj ) ) {
    // use object if already an array
    return obj;
  }

  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
  if ( isArrayLike ) {
    // convert nodeList to array
    return arraySlice.call( obj );
  }

  // array of single index
  return [ obj ];
}

// -------------------------- imagesLoaded -------------------------- //

/**
 * @param {Array, Element, NodeList, String} elem
 * @param {Object or Function} options - if function, use as callback
 * @param {Function} onAlways - callback function
 */
function ImagesLoaded( elem, options, onAlways ) {
  // coerce ImagesLoaded() without new, to be new ImagesLoaded()
  if ( !( this instanceof ImagesLoaded ) ) {
    return new ImagesLoaded( elem, options, onAlways );
  }
  // use elem as selector string
  var queryElem = elem;
  if ( typeof elem == 'string' ) {
    queryElem = document.querySelectorAll( elem );
  }
  // bail if bad element
  if ( !queryElem ) {
    console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );
    return;
  }

  this.elements = makeArray( queryElem );
  this.options = extend( {}, this.options );
  // shift arguments if no options set
  if ( typeof options == 'function' ) {
    onAlways = options;
  } else {
    extend( this.options, options );
  }

  if ( onAlways ) {
    this.on( 'always', onAlways );
  }

  this.getImages();

  if ( $ ) {
    // add jQuery Deferred object
    this.jqDeferred = new $.Deferred();
  }

  // HACK check async to allow time to bind listeners
  setTimeout( this.check.bind( this ) );
}

ImagesLoaded.prototype = Object.create( EvEmitter.prototype );

ImagesLoaded.prototype.options = {};

ImagesLoaded.prototype.getImages = function() {
  this.images = [];

  // filter & find items if we have an item selector
  this.elements.forEach( this.addElementImages, this );
};

/**
 * @param {Node} element
 */
ImagesLoaded.prototype.addElementImages = function( elem ) {
  // filter siblings
  if ( elem.nodeName == 'IMG' ) {
    this.addImage( elem );
  }
  // get background image on element
  if ( this.options.background === true ) {
    this.addElementBackgroundImages( elem );
  }

  // find children
  // no non-element nodes, #143
  var nodeType = elem.nodeType;
  if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
    return;
  }
  var childImgs = elem.querySelectorAll('img');
  // concat childElems to filterFound array
  for ( var i=0; i < childImgs.length; i++ ) {
    var img = childImgs[i];
    this.addImage( img );
  }

  // get child background images
  if ( typeof this.options.background == 'string' ) {
    var children = elem.querySelectorAll( this.options.background );
    for ( i=0; i < children.length; i++ ) {
      var child = children[i];
      this.addElementBackgroundImages( child );
    }
  }
};

var elementNodeTypes = {
  1: true,
  9: true,
  11: true
};

ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
  var style = getComputedStyle( elem );
  if ( !style ) {
    // Firefox returns null if in a hidden iframe https://bugzil.la/548397
    return;
  }
  // get url inside url("...")
  var reURL = /url\((['"])?(.*?)\1\)/gi;
  var matches = reURL.exec( style.backgroundImage );
  while ( matches !== null ) {
    var url = matches && matches[2];
    if ( url ) {
      this.addBackground( url, elem );
    }
    matches = reURL.exec( style.backgroundImage );
  }
};

/**
 * @param {Image} img
 */
ImagesLoaded.prototype.addImage = function( img ) {
  var loadingImage = new LoadingImage( img );
  this.images.push( loadingImage );
};

ImagesLoaded.prototype.addBackground = function( url, elem ) {
  var background = new Background( url, elem );
  this.images.push( background );
};

ImagesLoaded.prototype.check = function() {
  var _this = this;
  this.progressedCount = 0;
  this.hasAnyBroken = false;
  // complete if no images
  if ( !this.images.length ) {
    this.complete();
    return;
  }

  function onProgress( image, elem, message ) {
    // HACK - Chrome triggers event before object properties have changed. #83
    setTimeout( function() {
      _this.progress( image, elem, message );
    });
  }

  this.images.forEach( function( loadingImage ) {
    loadingImage.once( 'progress', onProgress );
    loadingImage.check();
  });
};

ImagesLoaded.prototype.progress = function( image, elem, message ) {
  this.progressedCount++;
  this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
  // progress event
  this.emitEvent( 'progress', [ this, image, elem ] );
  if ( this.jqDeferred && this.jqDeferred.notify ) {
    this.jqDeferred.notify( this, image );
  }
  // check if completed
  if ( this.progressedCount == this.images.length ) {
    this.complete();
  }

  if ( this.options.debug && console ) {
    console.log( 'progress: ' + message, image, elem );
  }
};

ImagesLoaded.prototype.complete = function() {
  var eventName = this.hasAnyBroken ? 'fail' : 'done';
  this.isComplete = true;
  this.emitEvent( eventName, [ this ] );
  this.emitEvent( 'always', [ this ] );
  if ( this.jqDeferred ) {
    var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
    this.jqDeferred[ jqMethod ]( this );
  }
};

// --------------------------  -------------------------- //

function LoadingImage( img ) {
  this.img = img;
}

LoadingImage.prototype = Object.create( EvEmitter.prototype );

LoadingImage.prototype.check = function() {
  // If complete is true and browser supports natural sizes,
  // try to check for image status manually.
  var isComplete = this.getIsImageComplete();
  if ( isComplete ) {
    // report based on naturalWidth
    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
    return;
  }

  // If none of the checks above matched, simulate loading on detached element.
  this.proxyImage = new Image();
  this.proxyImage.addEventListener( 'load', this );
  this.proxyImage.addEventListener( 'error', this );
  // bind to image as well for Firefox. #191
  this.img.addEventListener( 'load', this );
  this.img.addEventListener( 'error', this );
  this.proxyImage.src = this.img.src;
};

LoadingImage.prototype.getIsImageComplete = function() {
  // check for non-zero, non-undefined naturalWidth
  // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
  return this.img.complete && this.img.naturalWidth;
};

LoadingImage.prototype.confirm = function( isLoaded, message ) {
  this.isLoaded = isLoaded;
  this.emitEvent( 'progress', [ this, this.img, message ] );
};

// ----- events ----- //

// trigger specified handler for event type
LoadingImage.prototype.handleEvent = function( event ) {
  var method = 'on' + event.type;
  if ( this[ method ] ) {
    this[ method ]( event );
  }
};

LoadingImage.prototype.onload = function() {
  this.confirm( true, 'onload' );
  this.unbindEvents();
};

LoadingImage.prototype.onerror = function() {
  this.confirm( false, 'onerror' );
  this.unbindEvents();
};

LoadingImage.prototype.unbindEvents = function() {
  this.proxyImage.removeEventListener( 'load', this );
  this.proxyImage.removeEventListener( 'error', this );
  this.img.removeEventListener( 'load', this );
  this.img.removeEventListener( 'error', this );
};

// -------------------------- Background -------------------------- //

function Background( url, element ) {
  this.url = url;
  this.element = element;
  this.img = new Image();
}

// inherit LoadingImage prototype
Background.prototype = Object.create( LoadingImage.prototype );

Background.prototype.check = function() {
  this.img.addEventListener( 'load', this );
  this.img.addEventListener( 'error', this );
  this.img.src = this.url;
  // check if image is already complete
  var isComplete = this.getIsImageComplete();
  if ( isComplete ) {
    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
    this.unbindEvents();
  }
};

Background.prototype.unbindEvents = function() {
  this.img.removeEventListener( 'load', this );
  this.img.removeEventListener( 'error', this );
};

Background.prototype.confirm = function( isLoaded, message ) {
  this.isLoaded = isLoaded;
  this.emitEvent( 'progress', [ this, this.element, message ] );
};

// -------------------------- jQuery -------------------------- //

ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
  jQuery = jQuery || window.jQuery;
  if ( !jQuery ) {
    return;
  }
  // set local variable
  $ = jQuery;
  // $().imagesLoaded()
  $.fn.imagesLoaded = function( options, callback ) {
    var instance = new ImagesLoaded( this, options, callback );
    return instance.jqDeferred.promise( $(this) );
  };
};
// try making plugin
ImagesLoaded.makeJQueryPlugin();

// --------------------------  -------------------------- //

return ImagesLoaded;

});

},{"ev-emitter":207}],213:[function(require,module,exports){
/*!
 * jQuery Mousewheel 3.1.13
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 */

(function (factory) {
    if ( typeof define === 'function' && define.amd ) {
        // AMD. Register as an anonymous module.
        define(['jquery'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports = factory;
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {

    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
        slice  = Array.prototype.slice,
        nullLowestDeltaTimeout, lowestDelta;

    if ( $.event.fixHooks ) {
        for ( var i = toFix.length; i; ) {
            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
        }
    }

    var special = $.event.special.mousewheel = {
        version: '3.1.12',

        setup: function() {
            if ( this.addEventListener ) {
                for ( var i = toBind.length; i; ) {
                    this.addEventListener( toBind[--i], handler, false );
                }
            } else {
                this.onmousewheel = handler;
            }
            // Store the line height and page height for this particular element
            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
        },

        teardown: function() {
            if ( this.removeEventListener ) {
                for ( var i = toBind.length; i; ) {
                    this.removeEventListener( toBind[--i], handler, false );
                }
            } else {
                this.onmousewheel = null;
            }
            // Clean up the data we added to the element
            $.removeData(this, 'mousewheel-line-height');
            $.removeData(this, 'mousewheel-page-height');
        },

        getLineHeight: function(elem) {
            var $elem = $(elem),
                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
            if (!$parent.length) {
                $parent = $('body');
            }
            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
        },

        getPageHeight: function(elem) {
            return $(elem).height();
        },

        settings: {
            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
            normalizeOffset: true  // calls getBoundingClientRect for each event
        }
    };

    $.fn.extend({
        mousewheel: function(fn) {
            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
        },

        unmousewheel: function(fn) {
            return this.unbind('mousewheel', fn);
        }
    });


    function handler(event) {
        var orgEvent   = event || window.event,
            args       = slice.call(arguments, 1),
            delta      = 0,
            deltaX     = 0,
            deltaY     = 0,
            absDelta   = 0,
            offsetX    = 0,
            offsetY    = 0;
        event = $.event.fix(orgEvent);
        event.type = 'mousewheel';

        // Old school scrollwheel delta
        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }

        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
            deltaX = deltaY * -1;
            deltaY = 0;
        }

        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
        delta = deltaY === 0 ? deltaX : deltaY;

        // New school wheel delta (wheel event)
        if ( 'deltaY' in orgEvent ) {
            deltaY = orgEvent.deltaY * -1;
            delta  = deltaY;
        }
        if ( 'deltaX' in orgEvent ) {
            deltaX = orgEvent.deltaX;
            if ( deltaY === 0 ) { delta  = deltaX * -1; }
        }

        // No change actually happened, no reason to go any further
        if ( deltaY === 0 && deltaX === 0 ) { return; }

        // Need to convert lines and pages to pixels if we aren't already in pixels
        // There are three delta modes:
        //   * deltaMode 0 is by pixels, nothing to do
        //   * deltaMode 1 is by lines
        //   * deltaMode 2 is by pages
        if ( orgEvent.deltaMode === 1 ) {
            var lineHeight = $.data(this, 'mousewheel-line-height');
            delta  *= lineHeight;
            deltaY *= lineHeight;
            deltaX *= lineHeight;
        } else if ( orgEvent.deltaMode === 2 ) {
            var pageHeight = $.data(this, 'mousewheel-page-height');
            delta  *= pageHeight;
            deltaY *= pageHeight;
            deltaX *= pageHeight;
        }

        // Store lowest absolute delta to normalize the delta values
        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );

        if ( !lowestDelta || absDelta < lowestDelta ) {
            lowestDelta = absDelta;

            // Adjust older deltas if necessary
            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
                lowestDelta /= 40;
            }
        }

        // Adjust older deltas if necessary
        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
            // Divide all the things by 40!
            delta  /= 40;
            deltaX /= 40;
            deltaY /= 40;
        }

        // Get a whole, normalized value for the deltas
        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);

        // Normalise offsetX and offsetY properties
        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
            var boundingRect = this.getBoundingClientRect();
            offsetX = event.clientX - boundingRect.left;
            offsetY = event.clientY - boundingRect.top;
        }

        // Add information to the event object
        event.deltaX = deltaX;
        event.deltaY = deltaY;
        event.deltaFactor = lowestDelta;
        event.offsetX = offsetX;
        event.offsetY = offsetY;
        // Go ahead and set deltaMode to 0 since we converted to pixels
        // Although this is a little odd since we overwrite the deltaX/Y
        // properties with normalized deltas.
        event.deltaMode = 0;

        // Add event and delta to the front of the arguments
        args.unshift(event, delta, deltaX, deltaY);

        // Clearout lowestDelta after sometime to better
        // handle multiple device types that give different
        // a different lowestDelta
        // Ex: trackpad = 3 and mouse wheel = 120
        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);

        return ($.event.dispatch || $.event.handle).apply(this, args);
    }

    function nullLowestDelta() {
        lowestDelta = null;
    }

    function shouldAdjustOldDeltas(orgEvent, absDelta) {
        // If this is an older event and the delta is divisable by 120,
        // then we are assuming that the browser is treating this as an
        // older mouse wheel event and that we should divide the deltas
        // by 40 to try and get a more usable deltaFactor.
        // Side note, this actually impacts the reported scroll distance
        // in older browsers and can cause scrolling to be slower than native.
        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
    }

}));

},{}],214:[function(require,module,exports){
/*!
 * jQuery JavaScript Library v2.2.4
 * http://jquery.com/
 *
 * Includes Sizzle.js
 * http://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2016-05-20T17:23Z
 */

(function( global, factory ) {

	if ( typeof module === "object" && typeof module.exports === "object" ) {
		// For CommonJS and CommonJS-like environments where a proper `window`
		// is present, execute the factory and get jQuery.
		// For environments that do not have a `window` with a `document`
		// (such as Node.js), expose a factory as module.exports.
		// This accentuates the need for the creation of a real `window`.
		// e.g. var jQuery = require("jquery")(window);
		// See ticket #14549 for more info.
		module.exports = global.document ?
			factory( global, true ) :
			function( w ) {
				if ( !w.document ) {
					throw new Error( "jQuery requires a window with a document" );
				}
				return factory( w );
			};
	} else {
		factory( global );
	}

// Pass this if window is not defined yet
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {

// Support: Firefox 18+
// Can't be in strict mode, several libs including ASP.NET trace
// the stack via arguments.caller.callee and Firefox dies if
// you try to trace through "use strict" call chains. (#13335)
//"use strict";
var arr = [];

var document = window.document;

var slice = arr.slice;

var concat = arr.concat;

var push = arr.push;

var indexOf = arr.indexOf;

var class2type = {};

var toString = class2type.toString;

var hasOwn = class2type.hasOwnProperty;

var support = {};



var
	version = "2.2.4",

	// Define a local copy of jQuery
	jQuery = function( selector, context ) {

		// The jQuery object is actually just the init constructor 'enhanced'
		// Need init if jQuery is called (just allow error to be thrown if not included)
		return new jQuery.fn.init( selector, context );
	},

	// Support: Android<4.1
	// Make sure we trim BOM and NBSP
	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,

	// Matches dashed string for camelizing
	rmsPrefix = /^-ms-/,
	rdashAlpha = /-([\da-z])/gi,

	// Used by jQuery.camelCase as callback to replace()
	fcamelCase = function( all, letter ) {
		return letter.toUpperCase();
	};

jQuery.fn = jQuery.prototype = {

	// The current version of jQuery being used
	jquery: version,

	constructor: jQuery,

	// Start with an empty selector
	selector: "",

	// The default length of a jQuery object is 0
	length: 0,

	toArray: function() {
		return slice.call( this );
	},

	// Get the Nth element in the matched element set OR
	// Get the whole matched element set as a clean array
	get: function( num ) {
		return num != null ?

			// Return just the one element from the set
			( num < 0 ? this[ num + this.length ] : this[ num ] ) :

			// Return all the elements in a clean array
			slice.call( this );
	},

	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {

		// Build a new jQuery matched element set
		var ret = jQuery.merge( this.constructor(), elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;
		ret.context = this.context;

		// Return the newly-formed element set
		return ret;
	},

	// Execute a callback for every element in the matched set.
	each: function( callback ) {
		return jQuery.each( this, callback );
	},

	map: function( callback ) {
		return this.pushStack( jQuery.map( this, function( elem, i ) {
			return callback.call( elem, i, elem );
		} ) );
	},

	slice: function() {
		return this.pushStack( slice.apply( this, arguments ) );
	},

	first: function() {
		return this.eq( 0 );
	},

	last: function() {
		return this.eq( -1 );
	},

	eq: function( i ) {
		var len = this.length,
			j = +i + ( i < 0 ? len : 0 );
		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
	},

	end: function() {
		return this.prevObject || this.constructor();
	},

	// For internal use only.
	// Behaves like an Array's method, not like a jQuery method.
	push: push,
	sort: arr.sort,
	splice: arr.splice
};

jQuery.extend = jQuery.fn.extend = function() {
	var options, name, src, copy, copyIsArray, clone,
		target = arguments[ 0 ] || {},
		i = 1,
		length = arguments.length,
		deep = false;

	// Handle a deep copy situation
	if ( typeof target === "boolean" ) {
		deep = target;

		// Skip the boolean and the target
		target = arguments[ i ] || {};
		i++;
	}

	// Handle case when target is a string or something (possible in deep copy)
	if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
		target = {};
	}

	// Extend jQuery itself if only one argument is passed
	if ( i === length ) {
		target = this;
		i--;
	}

	for ( ; i < length; i++ ) {

		// Only deal with non-null/undefined values
		if ( ( options = arguments[ i ] ) != null ) {

			// Extend the base object
			for ( name in options ) {
				src = target[ name ];
				copy = options[ name ];

				// Prevent never-ending loop
				if ( target === copy ) {
					continue;
				}

				// Recurse if we're merging plain objects or arrays
				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
					( copyIsArray = jQuery.isArray( copy ) ) ) ) {

					if ( copyIsArray ) {
						copyIsArray = false;
						clone = src && jQuery.isArray( src ) ? src : [];

					} else {
						clone = src && jQuery.isPlainObject( src ) ? src : {};
					}

					// Never move original objects, clone them
					target[ name ] = jQuery.extend( deep, clone, copy );

				// Don't bring in undefined values
				} else if ( copy !== undefined ) {
					target[ name ] = copy;
				}
			}
		}
	}

	// Return the modified object
	return target;
};

jQuery.extend( {

	// Unique for each copy of jQuery on the page
	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),

	// Assume jQuery is ready without the ready module
	isReady: true,

	error: function( msg ) {
		throw new Error( msg );
	},

	noop: function() {},

	isFunction: function( obj ) {
		return jQuery.type( obj ) === "function";
	},

	isArray: Array.isArray,

	isWindow: function( obj ) {
		return obj != null && obj === obj.window;
	},

	isNumeric: function( obj ) {

		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
		// subtraction forces infinities to NaN
		// adding 1 corrects loss of precision from parseFloat (#15100)
		var realStringObj = obj && obj.toString();
		return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
	},

	isPlainObject: function( obj ) {
		var key;

		// Not plain objects:
		// - Any object or value whose internal [[Class]] property is not "[object Object]"
		// - DOM nodes
		// - window
		if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
			return false;
		}

		// Not own constructor property must be Object
		if ( obj.constructor &&
				!hasOwn.call( obj, "constructor" ) &&
				!hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) {
			return false;
		}

		// Own properties are enumerated firstly, so to speed up,
		// if last one is own, then all properties are own
		for ( key in obj ) {}

		return key === undefined || hasOwn.call( obj, key );
	},

	isEmptyObject: function( obj ) {
		var name;
		for ( name in obj ) {
			return false;
		}
		return true;
	},

	type: function( obj ) {
		if ( obj == null ) {
			return obj + "";
		}

		// Support: Android<4.0, iOS<6 (functionish RegExp)
		return typeof obj === "object" || typeof obj === "function" ?
			class2type[ toString.call( obj ) ] || "object" :
			typeof obj;
	},

	// Evaluates a script in a global context
	globalEval: function( code ) {
		var script,
			indirect = eval;

		code = jQuery.trim( code );

		if ( code ) {

			// If the code includes a valid, prologue position
			// strict mode pragma, execute code by injecting a
			// script tag into the document.
			if ( code.indexOf( "use strict" ) === 1 ) {
				script = document.createElement( "script" );
				script.text = code;
				document.head.appendChild( script ).parentNode.removeChild( script );
			} else {

				// Otherwise, avoid the DOM node creation, insertion
				// and removal by using an indirect global eval

				indirect( code );
			}
		}
	},

	// Convert dashed to camelCase; used by the css and data modules
	// Support: IE9-11+
	// Microsoft forgot to hump their vendor prefix (#9572)
	camelCase: function( string ) {
		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
	},

	nodeName: function( elem, name ) {
		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
	},

	each: function( obj, callback ) {
		var length, i = 0;

		if ( isArrayLike( obj ) ) {
			length = obj.length;
			for ( ; i < length; i++ ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		} else {
			for ( i in obj ) {
				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
					break;
				}
			}
		}

		return obj;
	},

	// Support: Android<4.1
	trim: function( text ) {
		return text == null ?
			"" :
			( text + "" ).replace( rtrim, "" );
	},

	// results is for internal usage only
	makeArray: function( arr, results ) {
		var ret = results || [];

		if ( arr != null ) {
			if ( isArrayLike( Object( arr ) ) ) {
				jQuery.merge( ret,
					typeof arr === "string" ?
					[ arr ] : arr
				);
			} else {
				push.call( ret, arr );
			}
		}

		return ret;
	},

	inArray: function( elem, arr, i ) {
		return arr == null ? -1 : indexOf.call( arr, elem, i );
	},

	merge: function( first, second ) {
		var len = +second.length,
			j = 0,
			i = first.length;

		for ( ; j < len; j++ ) {
			first[ i++ ] = second[ j ];
		}

		first.length = i;

		return first;
	},

	grep: function( elems, callback, invert ) {
		var callbackInverse,
			matches = [],
			i = 0,
			length = elems.length,
			callbackExpect = !invert;

		// Go through the array, only saving the items
		// that pass the validator function
		for ( ; i < length; i++ ) {
			callbackInverse = !callback( elems[ i ], i );
			if ( callbackInverse !== callbackExpect ) {
				matches.push( elems[ i ] );
			}
		}

		return matches;
	},

	// arg is for internal usage only
	map: function( elems, callback, arg ) {
		var length, value,
			i = 0,
			ret = [];

		// Go through the array, translating each of the items to their new values
		if ( isArrayLike( elems ) ) {
			length = elems.length;
			for ( ; i < length; i++ ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}

		// Go through every key on the object,
		} else {
			for ( i in elems ) {
				value = callback( elems[ i ], i, arg );

				if ( value != null ) {
					ret.push( value );
				}
			}
		}

		// Flatten any nested arrays
		return concat.apply( [], ret );
	},

	// A global GUID counter for objects
	guid: 1,

	// Bind a function to a context, optionally partially applying any
	// arguments.
	proxy: function( fn, context ) {
		var tmp, args, proxy;

		if ( typeof context === "string" ) {
			tmp = fn[ context ];
			context = fn;
			fn = tmp;
		}

		// Quick check to determine if target is callable, in the spec
		// this throws a TypeError, but we will just return undefined.
		if ( !jQuery.isFunction( fn ) ) {
			return undefined;
		}

		// Simulated bind
		args = slice.call( arguments, 2 );
		proxy = function() {
			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
		};

		// Set the guid of unique handler to the same of original handler, so it can be removed
		proxy.guid = fn.guid = fn.guid || jQuery.guid++;

		return proxy;
	},

	now: Date.now,

	// jQuery.support is not used in Core but other projects attach their
	// properties to it so it needs to exist.
	support: support
} );

// JSHint would error on this code due to the Symbol not being defined in ES5.
// Defining this global in .jshintrc would create a danger of using the global
// unguarded in another place, it seems safer to just disable JSHint for these
// three lines.
/* jshint ignore: start */
if ( typeof Symbol === "function" ) {
	jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
}
/* jshint ignore: end */

// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
	class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );

function isArrayLike( obj ) {

	// Support: iOS 8.2 (not reproducible in simulator)
	// `in` check used to prevent JIT error (gh-2145)
	// hasOwn isn't used here due to false negatives
	// regarding Nodelist length in IE
	var length = !!obj && "length" in obj && obj.length,
		type = jQuery.type( obj );

	if ( type === "function" || jQuery.isWindow( obj ) ) {
		return false;
	}

	return type === "array" || length === 0 ||
		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
var Sizzle =
/*!
 * Sizzle CSS Selector Engine v2.2.1
 * http://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2015-10-17
 */
(function( window ) {

var i,
	support,
	Expr,
	getText,
	isXML,
	tokenize,
	compile,
	select,
	outermostContext,
	sortInput,
	hasDuplicate,

	// Local document vars
	setDocument,
	document,
	docElem,
	documentIsHTML,
	rbuggyQSA,
	rbuggyMatches,
	matches,
	contains,

	// Instance-specific data
	expando = "sizzle" + 1 * new Date(),
	preferredDoc = window.document,
	dirruns = 0,
	done = 0,
	classCache = createCache(),
	tokenCache = createCache(),
	compilerCache = createCache(),
	sortOrder = function( a, b ) {
		if ( a === b ) {
			hasDuplicate = true;
		}
		return 0;
	},

	// General-purpose constants
	MAX_NEGATIVE = 1 << 31,

	// Instance methods
	hasOwn = ({}).hasOwnProperty,
	arr = [],
	pop = arr.pop,
	push_native = arr.push,
	push = arr.push,
	slice = arr.slice,
	// Use a stripped-down indexOf as it's faster than native
	// http://jsperf.com/thor-indexof-vs-for/5
	indexOf = function( list, elem ) {
		var i = 0,
			len = list.length;
		for ( ; i < len; i++ ) {
			if ( list[i] === elem ) {
				return i;
			}
		}
		return -1;
	},

	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",

	// Regular expressions

	// http://www.w3.org/TR/css3-selectors/#whitespace
	whitespace = "[\\x20\\t\\r\\n\\f]",

	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
	identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",

	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
		// Operator (capture 2)
		"*([*^$|!~]?=)" + whitespace +
		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
		"*\\]",

	pseudos = ":(" + identifier + ")(?:\\((" +
		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
		// 1. quoted (capture 3; capture 4 or capture 5)
		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
		// 2. simple (capture 6)
		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
		// 3. anything else (capture 2)
		".*" +
		")\\)|)",

	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
	rwhitespace = new RegExp( whitespace + "+", "g" ),
	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),

	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),

	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),

	rpseudo = new RegExp( pseudos ),
	ridentifier = new RegExp( "^" + identifier + "$" ),

	matchExpr = {
		"ID": new RegExp( "^#(" + identifier + ")" ),
		"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
		"ATTR": new RegExp( "^" + attributes ),
		"PSEUDO": new RegExp( "^" + pseudos ),
		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
		// For use in libraries implementing .is()
		// We use this for POS matching in `select`
		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
	},

	rinputs = /^(?:input|select|textarea|button)$/i,
	rheader = /^h\d$/i,

	rnative = /^[^{]+\{\s*\[native \w/,

	// Easily-parseable/retrievable ID or TAG or CLASS selectors
	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,

	rsibling = /[+~]/,
	rescape = /'|\\/g,

	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
	funescape = function( _, escaped, escapedWhitespace ) {
		var high = "0x" + escaped - 0x10000;
		// NaN means non-codepoint
		// Support: Firefox<24
		// Workaround erroneous numeric interpretation of +"0x"
		return high !== high || escapedWhitespace ?
			escaped :
			high < 0 ?
				// BMP codepoint
				String.fromCharCode( high + 0x10000 ) :
				// Supplemental Plane codepoint (surrogate pair)
				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
	},

	// Used for iframes
	// See setDocument()
	// Removing the function wrapper causes a "Permission Denied"
	// error in IE
	unloadHandler = function() {
		setDocument();
	};

// Optimize for push.apply( _, NodeList )
try {
	push.apply(
		(arr = slice.call( preferredDoc.childNodes )),
		preferredDoc.childNodes
	);
	// Support: Android<4.0
	// Detect silently failing push.apply
	arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
	push = { apply: arr.length ?

		// Leverage slice if possible
		function( target, els ) {
			push_native.apply( target, slice.call(els) );
		} :

		// Support: IE<9
		// Otherwise append directly
		function( target, els ) {
			var j = target.length,
				i = 0;
			// Can't trust NodeList.length
			while ( (target[j++] = els[i++]) ) {}
			target.length = j - 1;
		}
	};
}

function Sizzle( selector, context, results, seed ) {
	var m, i, elem, nid, nidselect, match, groups, newSelector,
		newContext = context && context.ownerDocument,

		// nodeType defaults to 9, since context defaults to document
		nodeType = context ? context.nodeType : 9;

	results = results || [];

	// Return early from calls with invalid selector or context
	if ( typeof selector !== "string" || !selector ||
		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

		return results;
	}

	// Try to shortcut find operations (as opposed to filters) in HTML documents
	if ( !seed ) {

		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
			setDocument( context );
		}
		context = context || document;

		if ( documentIsHTML ) {

			// If the selector is sufficiently simple, try using a "get*By*" DOM method
			// (excepting DocumentFragment context, where the methods don't exist)
			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {

				// ID selector
				if ( (m = match[1]) ) {

					// Document context
					if ( nodeType === 9 ) {
						if ( (elem = context.getElementById( m )) ) {

							// Support: IE, Opera, Webkit
							// TODO: identify versions
							// getElementById can match elements by name instead of ID
							if ( elem.id === m ) {
								results.push( elem );
								return results;
							}
						} else {
							return results;
						}

					// Element context
					} else {

						// Support: IE, Opera, Webkit
						// TODO: identify versions
						// getElementById can match elements by name instead of ID
						if ( newContext && (elem = newContext.getElementById( m )) &&
							contains( context, elem ) &&
							elem.id === m ) {

							results.push( elem );
							return results;
						}
					}

				// Type selector
				} else if ( match[2] ) {
					push.apply( results, context.getElementsByTagName( selector ) );
					return results;

				// Class selector
				} else if ( (m = match[3]) && support.getElementsByClassName &&
					context.getElementsByClassName ) {

					push.apply( results, context.getElementsByClassName( m ) );
					return results;
				}
			}

			// Take advantage of querySelectorAll
			if ( support.qsa &&
				!compilerCache[ selector + " " ] &&
				(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {

				if ( nodeType !== 1 ) {
					newContext = context;
					newSelector = selector;

				// qSA looks outside Element context, which is not what we want
				// Thanks to Andrew Dupont for this workaround technique
				// Support: IE <=8
				// Exclude object elements
				} else if ( context.nodeName.toLowerCase() !== "object" ) {

					// Capture the context ID, setting it first if necessary
					if ( (nid = context.getAttribute( "id" )) ) {
						nid = nid.replace( rescape, "\\$&" );
					} else {
						context.setAttribute( "id", (nid = expando) );
					}

					// Prefix every selector in the list
					groups = tokenize( selector );
					i = groups.length;
					nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
					while ( i-- ) {
						groups[i] = nidselect + " " + toSelector( groups[i] );
					}
					newSelector = groups.join( "," );

					// Expand context for sibling selectors
					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
						context;
				}

				if ( newSelector ) {
					try {
						push.apply( results,
							newContext.querySelectorAll( newSelector )
						);
						return results;
					} catch ( qsaError ) {
					} finally {
						if ( nid === expando ) {
							context.removeAttribute( "id" );
						}
					}
				}
			}
		}
	}

	// All others
	return select( selector.replace( rtrim, "$1" ), context, results, seed );
}

/**
 * Create key-value caches of limited size
 * @returns {function(string, object)} Returns the Object data after storing it on itself with
 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
 *	deleting the oldest entry
 */
function createCache() {
	var keys = [];

	function cache( key, value ) {
		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
		if ( keys.push( key + " " ) > Expr.cacheLength ) {
			// Only keep the most recent entries
			delete cache[ keys.shift() ];
		}
		return (cache[ key + " " ] = value);
	}
	return cache;
}

/**
 * Mark a function for special use by Sizzle
 * @param {Function} fn The function to mark
 */
function markFunction( fn ) {
	fn[ expando ] = true;
	return fn;
}

/**
 * Support testing using an element
 * @param {Function} fn Passed the created div and expects a boolean result
 */
function assert( fn ) {
	var div = document.createElement("div");

	try {
		return !!fn( div );
	} catch (e) {
		return false;
	} finally {
		// Remove from its parent by default
		if ( div.parentNode ) {
			div.parentNode.removeChild( div );
		}
		// release memory in IE
		div = null;
	}
}

/**
 * Adds the same handler for all of the specified attrs
 * @param {String} attrs Pipe-separated list of attributes
 * @param {Function} handler The method that will be applied
 */
function addHandle( attrs, handler ) {
	var arr = attrs.split("|"),
		i = arr.length;

	while ( i-- ) {
		Expr.attrHandle[ arr[i] ] = handler;
	}
}

/**
 * Checks document order of two siblings
 * @param {Element} a
 * @param {Element} b
 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
 */
function siblingCheck( a, b ) {
	var cur = b && a,
		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
			( ~b.sourceIndex || MAX_NEGATIVE ) -
			( ~a.sourceIndex || MAX_NEGATIVE );

	// Use IE sourceIndex if available on both nodes
	if ( diff ) {
		return diff;
	}

	// Check if b follows a
	if ( cur ) {
		while ( (cur = cur.nextSibling) ) {
			if ( cur === b ) {
				return -1;
			}
		}
	}

	return a ? 1 : -1;
}

/**
 * Returns a function to use in pseudos for input types
 * @param {String} type
 */
function createInputPseudo( type ) {
	return function( elem ) {
		var name = elem.nodeName.toLowerCase();
		return name === "input" && elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for buttons
 * @param {String} type
 */
function createButtonPseudo( type ) {
	return function( elem ) {
		var name = elem.nodeName.toLowerCase();
		return (name === "input" || name === "button") && elem.type === type;
	};
}

/**
 * Returns a function to use in pseudos for positionals
 * @param {Function} fn
 */
function createPositionalPseudo( fn ) {
	return markFunction(function( argument ) {
		argument = +argument;
		return markFunction(function( seed, matches ) {
			var j,
				matchIndexes = fn( [], seed.length, argument ),
				i = matchIndexes.length;

			// Match elements found at the specified indexes
			while ( i-- ) {
				if ( seed[ (j = matchIndexes[i]) ] ) {
					seed[j] = !(matches[j] = seed[j]);
				}
			}
		});
	});
}

/**
 * Checks a node for validity as a Sizzle context
 * @param {Element|Object=} context
 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
 */
function testContext( context ) {
	return context && typeof context.getElementsByTagName !== "undefined" && context;
}

// Expose support vars for convenience
support = Sizzle.support = {};

/**
 * Detects XML nodes
 * @param {Element|Object} elem An element or a document
 * @returns {Boolean} True iff elem is a non-HTML XML node
 */
isXML = Sizzle.isXML = function( elem ) {
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833)
	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
	return documentElement ? documentElement.nodeName !== "HTML" : false;
};

/**
 * Sets document-related variables once based on the current document
 * @param {Element|Object} [doc] An element or document object to use to set the document
 * @returns {Object} Returns the current document
 */
setDocument = Sizzle.setDocument = function( node ) {
	var hasCompare, parent,
		doc = node ? node.ownerDocument || node : preferredDoc;

	// Return early if doc is invalid or already selected
	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
		return document;
	}

	// Update global variables
	document = doc;
	docElem = document.documentElement;
	documentIsHTML = !isXML( document );

	// Support: IE 9-11, Edge
	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
	if ( (parent = document.defaultView) && parent.top !== parent ) {
		// Support: IE 11
		if ( parent.addEventListener ) {
			parent.addEventListener( "unload", unloadHandler, false );

		// Support: IE 9 - 10 only
		} else if ( parent.attachEvent ) {
			parent.attachEvent( "onunload", unloadHandler );
		}
	}

	/* Attributes
	---------------------------------------------------------------------- */

	// Support: IE<8
	// Verify that getAttribute really returns attributes and not properties
	// (excepting IE8 booleans)
	support.attributes = assert(function( div ) {
		div.className = "i";
		return !div.getAttribute("className");
	});

	/* getElement(s)By*
	---------------------------------------------------------------------- */

	// Check if getElementsByTagName("*") returns only elements
	support.getElementsByTagName = assert(function( div ) {
		div.appendChild( document.createComment("") );
		return !div.getElementsByTagName("*").length;
	});

	// Support: IE<9
	support.getElementsByClassName = rnative.test( document.getElementsByClassName );

	// Support: IE<10
	// Check if getElementById returns elements by name
	// The broken getElementById methods don't pick up programatically-set names,
	// so use a roundabout getElementsByName test
	support.getById = assert(function( div ) {
		docElem.appendChild( div ).id = expando;
		return !document.getElementsByName || !document.getElementsByName( expando ).length;
	});

	// ID find and filter
	if ( support.getById ) {
		Expr.find["ID"] = function( id, context ) {
			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
				var m = context.getElementById( id );
				return m ? [ m ] : [];
			}
		};
		Expr.filter["ID"] = function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				return elem.getAttribute("id") === attrId;
			};
		};
	} else {
		// Support: IE6/7
		// getElementById is not reliable as a find shortcut
		delete Expr.find["ID"];

		Expr.filter["ID"] =  function( id ) {
			var attrId = id.replace( runescape, funescape );
			return function( elem ) {
				var node = typeof elem.getAttributeNode !== "undefined" &&
					elem.getAttributeNode("id");
				return node && node.value === attrId;
			};
		};
	}

	// Tag
	Expr.find["TAG"] = support.getElementsByTagName ?
		function( tag, context ) {
			if ( typeof context.getElementsByTagName !== "undefined" ) {
				return context.getElementsByTagName( tag );

			// DocumentFragment nodes don't have gEBTN
			} else if ( support.qsa ) {
				return context.querySelectorAll( tag );
			}
		} :

		function( tag, context ) {
			var elem,
				tmp = [],
				i = 0,
				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
				results = context.getElementsByTagName( tag );

			// Filter out possible comments
			if ( tag === "*" ) {
				while ( (elem = results[i++]) ) {
					if ( elem.nodeType === 1 ) {
						tmp.push( elem );
					}
				}

				return tmp;
			}
			return results;
		};

	// Class
	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
			return context.getElementsByClassName( className );
		}
	};

	/* QSA/matchesSelector
	---------------------------------------------------------------------- */

	// QSA and matchesSelector support

	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
	rbuggyMatches = [];

	// qSa(:focus) reports false when true (Chrome 21)
	// We allow this because of a bug in IE8/9 that throws an error
	// whenever `document.activeElement` is accessed on an iframe
	// So, we allow :focus to pass through QSA all the time to avoid the IE error
	// See http://bugs.jquery.com/ticket/13378
	rbuggyQSA = [];

	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
		// Build QSA regex
		// Regex strategy adopted from Diego Perini
		assert(function( div ) {
			// Select is set to empty string on purpose
			// This is to test IE's treatment of not explicitly
			// setting a boolean content attribute,
			// since its presence should be enough
			// http://bugs.jquery.com/ticket/12359
			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
				"<select id='" + expando + "-\r\\' msallowcapture=''>" +
				"<option selected=''></option></select>";

			// Support: IE8, Opera 11-12.16
			// Nothing should be selected when empty strings follow ^= or $= or *=
			// The test attribute must be unknown in Opera but "safe" for WinRT
			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
			if ( div.querySelectorAll("[msallowcapture^='']").length ) {
				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
			}

			// Support: IE8
			// Boolean attributes and "value" are not treated correctly
			if ( !div.querySelectorAll("[selected]").length ) {
				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
			}

			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
				rbuggyQSA.push("~=");
			}

			// Webkit/Opera - :checked should return selected option elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":checked").length ) {
				rbuggyQSA.push(":checked");
			}

			// Support: Safari 8+, iOS 8+
			// https://bugs.webkit.org/show_bug.cgi?id=136851
			// In-page `selector#id sibing-combinator selector` fails
			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
				rbuggyQSA.push(".#.+[+~]");
			}
		});

		assert(function( div ) {
			// Support: Windows 8 Native Apps
			// The type and name attributes are restricted during .innerHTML assignment
			var input = document.createElement("input");
			input.setAttribute( "type", "hidden" );
			div.appendChild( input ).setAttribute( "name", "D" );

			// Support: IE8
			// Enforce case-sensitivity of name attribute
			if ( div.querySelectorAll("[name=d]").length ) {
				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
			}

			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
			// IE8 throws error here and will not see later tests
			if ( !div.querySelectorAll(":enabled").length ) {
				rbuggyQSA.push( ":enabled", ":disabled" );
			}

			// Opera 10-11 does not throw on post-comma invalid pseudos
			div.querySelectorAll("*,:x");
			rbuggyQSA.push(",.*:");
		});
	}

	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
		docElem.webkitMatchesSelector ||
		docElem.mozMatchesSelector ||
		docElem.oMatchesSelector ||
		docElem.msMatchesSelector) )) ) {

		assert(function( div ) {
			// Check to see if it's possible to do matchesSelector
			// on a disconnected node (IE 9)
			support.disconnectedMatch = matches.call( div, "div" );

			// This should fail with an exception
			// Gecko does not error, returns false instead
			matches.call( div, "[s!='']:x" );
			rbuggyMatches.push( "!=", pseudos );
		});
	}

	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );

	/* Contains
	---------------------------------------------------------------------- */
	hasCompare = rnative.test( docElem.compareDocumentPosition );

	// Element contains another
	// Purposefully self-exclusive
	// As in, an element does not contain itself
	contains = hasCompare || rnative.test( docElem.contains ) ?
		function( a, b ) {
			var adown = a.nodeType === 9 ? a.documentElement : a,
				bup = b && b.parentNode;
			return a === bup || !!( bup && bup.nodeType === 1 && (
				adown.contains ?
					adown.contains( bup ) :
					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
			));
		} :
		function( a, b ) {
			if ( b ) {
				while ( (b = b.parentNode) ) {
					if ( b === a ) {
						return true;
					}
				}
			}
			return false;
		};

	/* Sorting
	---------------------------------------------------------------------- */

	// Document order sorting
	sortOrder = hasCompare ?
	function( a, b ) {

		// Flag for duplicate removal
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		// Sort on method existence if only one input has compareDocumentPosition
		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
		if ( compare ) {
			return compare;
		}

		// Calculate position if both inputs belong to the same document
		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
			a.compareDocumentPosition( b ) :

			// Otherwise we know they are disconnected
			1;

		// Disconnected nodes
		if ( compare & 1 ||
			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {

			// Choose the first element that is related to our preferred document
			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
				return -1;
			}
			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
				return 1;
			}

			// Maintain original order
			return sortInput ?
				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
				0;
		}

		return compare & 4 ? -1 : 1;
	} :
	function( a, b ) {
		// Exit early if the nodes are identical
		if ( a === b ) {
			hasDuplicate = true;
			return 0;
		}

		var cur,
			i = 0,
			aup = a.parentNode,
			bup = b.parentNode,
			ap = [ a ],
			bp = [ b ];

		// Parentless nodes are either documents or disconnected
		if ( !aup || !bup ) {
			return a === document ? -1 :
				b === document ? 1 :
				aup ? -1 :
				bup ? 1 :
				sortInput ?
				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
				0;

		// If the nodes are siblings, we can do a quick check
		} else if ( aup === bup ) {
			return siblingCheck( a, b );
		}

		// Otherwise we need full lists of their ancestors for comparison
		cur = a;
		while ( (cur = cur.parentNode) ) {
			ap.unshift( cur );
		}
		cur = b;
		while ( (cur = cur.parentNode) ) {
			bp.unshift( cur );
		}

		// Walk down the tree looking for a discrepancy
		while ( ap[i] === bp[i] ) {
			i++;
		}

		return i ?
			// Do a sibling check if the nodes have a common ancestor
			siblingCheck( ap[i], bp[i] ) :

			// Otherwise nodes in our document sort first
			ap[i] === preferredDoc ? -1 :
			bp[i] === preferredDoc ? 1 :
			0;
	};

	return document;
};

Sizzle.matches = function( expr, elements ) {
	return Sizzle( expr, null, null, elements );
};

Sizzle.matchesSelector = function( elem, expr ) {
	// Set document vars if needed
	if ( ( elem.ownerDocument || elem ) !== document ) {
		setDocument( elem );
	}

	// Make sure that attribute selectors are quoted
	expr = expr.replace( rattributeQuotes, "='$1']" );

	if ( support.matchesSelector && documentIsHTML &&
		!compilerCache[ expr + " " ] &&
		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {

		try {
			var ret = matches.call( elem, expr );

			// IE 9's matchesSelector returns false on disconnected nodes
			if ( ret || support.disconnectedMatch ||
					// As well, disconnected nodes are said to be in a document
					// fragment in IE 9
					elem.document && elem.document.nodeType !== 11 ) {
				return ret;
			}
		} catch (e) {}
	}

	return Sizzle( expr, document, null, [ elem ] ).length > 0;
};

Sizzle.contains = function( context, elem ) {
	// Set document vars if needed
	if ( ( context.ownerDocument || context ) !== document ) {
		setDocument( context );
	}
	return contains( context, elem );
};

Sizzle.attr = function( elem, name ) {
	// Set document vars if needed
	if ( ( elem.ownerDocument || elem ) !== document ) {
		setDocument( elem );
	}

	var fn = Expr.attrHandle[ name.toLowerCase() ],
		// Don't get fooled by Object.prototype properties (jQuery #13807)
		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
			fn( elem, name, !documentIsHTML ) :
			undefined;

	return val !== undefined ?
		val :
		support.attributes || !documentIsHTML ?
			elem.getAttribute( name ) :
			(val = elem.getAttributeNode(name)) && val.specified ?
				val.value :
				null;
};

Sizzle.error = function( msg ) {
	throw new Error( "Syntax error, unrecognized expression: " + msg );
};

/**
 * Document sorting and removing duplicates
 * @param {ArrayLike} results
 */
Sizzle.uniqueSort = function( results ) {
	var elem,
		duplicates = [],
		j = 0,
		i = 0;

	// Unless we *know* we can detect duplicates, assume their presence
	hasDuplicate = !support.detectDuplicates;
	sortInput = !support.sortStable && results.slice( 0 );
	results.sort( sortOrder );

	if ( hasDuplicate ) {
		while ( (elem = results[i++]) ) {
			if ( elem === results[ i ] ) {
				j = duplicates.push( i );
			}
		}
		while ( j-- ) {
			results.splice( duplicates[ j ], 1 );
		}
	}

	// Clear input after sorting to release objects
	// See https://github.com/jquery/sizzle/pull/225
	sortInput = null;

	return results;
};

/**
 * Utility function for retrieving the text value of an array of DOM nodes
 * @param {Array|Element} elem
 */
getText = Sizzle.getText = function( elem ) {
	var node,
		ret = "",
		i = 0,
		nodeType = elem.nodeType;

	if ( !nodeType ) {
		// If no nodeType, this is expected to be an array
		while ( (node = elem[i++]) ) {
			// Do not traverse comment nodes
			ret += getText( node );
		}
	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
		// Use textContent for elements
		// innerText usage removed for consistency of new lines (jQuery #11153)
		if ( typeof elem.textContent === "string" ) {
			return elem.textContent;
		} else {
			// Traverse its children
			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
				ret += getText( elem );
			}
		}
	} else if ( nodeType === 3 || nodeType === 4 ) {
		return elem.nodeValue;
	}
	// Do not include comment or processing instruction nodes

	return ret;
};

Expr = Sizzle.selectors = {

	// Can be adjusted by the user
	cacheLength: 50,

	createPseudo: markFunction,

	match: matchExpr,

	attrHandle: {},

	find: {},

	relative: {
		">": { dir: "parentNode", first: true },
		" ": { dir: "parentNode" },
		"+": { dir: "previousSibling", first: true },
		"~": { dir: "previousSibling" }
	},

	preFilter: {
		"ATTR": function( match ) {
			match[1] = match[1].replace( runescape, funescape );

			// Move the given value to match[3] whether quoted or unquoted
			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );

			if ( match[2] === "~=" ) {
				match[3] = " " + match[3] + " ";
			}

			return match.slice( 0, 4 );
		},

		"CHILD": function( match ) {
			/* matches from matchExpr["CHILD"]
				1 type (only|nth|...)
				2 what (child|of-type)
				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
				4 xn-component of xn+y argument ([+-]?\d*n|)
				5 sign of xn-component
				6 x of xn-component
				7 sign of y-component
				8 y of y-component
			*/
			match[1] = match[1].toLowerCase();

			if ( match[1].slice( 0, 3 ) === "nth" ) {
				// nth-* requires argument
				if ( !match[3] ) {
					Sizzle.error( match[0] );
				}

				// numeric x and y parameters for Expr.filter.CHILD
				// remember that false/true cast respectively to 0/1
				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );

			// other types prohibit arguments
			} else if ( match[3] ) {
				Sizzle.error( match[0] );
			}

			return match;
		},

		"PSEUDO": function( match ) {
			var excess,
				unquoted = !match[6] && match[2];

			if ( matchExpr["CHILD"].test( match[0] ) ) {
				return null;
			}

			// Accept quoted arguments as-is
			if ( match[3] ) {
				match[2] = match[4] || match[5] || "";

			// Strip excess characters from unquoted arguments
			} else if ( unquoted && rpseudo.test( unquoted ) &&
				// Get excess from tokenize (recursively)
				(excess = tokenize( unquoted, true )) &&
				// advance to the next closing parenthesis
				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {

				// excess is a negative index
				match[0] = match[0].slice( 0, excess );
				match[2] = unquoted.slice( 0, excess );
			}

			// Return only captures needed by the pseudo filter method (type and argument)
			return match.slice( 0, 3 );
		}
	},

	filter: {

		"TAG": function( nodeNameSelector ) {
			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
			return nodeNameSelector === "*" ?
				function() { return true; } :
				function( elem ) {
					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
				};
		},

		"CLASS": function( className ) {
			var pattern = classCache[ className + " " ];

			return pattern ||
				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
				classCache( className, function( elem ) {
					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
				});
		},

		"ATTR": function( name, operator, check ) {
			return function( elem ) {
				var result = Sizzle.attr( elem, name );

				if ( result == null ) {
					return operator === "!=";
				}
				if ( !operator ) {
					return true;
				}

				result += "";

				return operator === "=" ? result === check :
					operator === "!=" ? result !== check :
					operator === "^=" ? check && result.indexOf( check ) === 0 :
					operator === "*=" ? check && result.indexOf( check ) > -1 :
					operator === "$=" ? check && result.slice( -check.length ) === check :
					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
					false;
			};
		},

		"CHILD": function( type, what, argument, first, last ) {
			var simple = type.slice( 0, 3 ) !== "nth",
				forward = type.slice( -4 ) !== "last",
				ofType = what === "of-type";

			return first === 1 && last === 0 ?

				// Shortcut for :nth-*(n)
				function( elem ) {
					return !!elem.parentNode;
				} :

				function( elem, context, xml ) {
					var cache, uniqueCache, outerCache, node, nodeIndex, start,
						dir = simple !== forward ? "nextSibling" : "previousSibling",
						parent = elem.parentNode,
						name = ofType && elem.nodeName.toLowerCase(),
						useCache = !xml && !ofType,
						diff = false;

					if ( parent ) {

						// :(first|last|only)-(child|of-type)
						if ( simple ) {
							while ( dir ) {
								node = elem;
								while ( (node = node[ dir ]) ) {
									if ( ofType ?
										node.nodeName.toLowerCase() === name :
										node.nodeType === 1 ) {

										return false;
									}
								}
								// Reverse direction for :only-* (if we haven't yet done so)
								start = dir = type === "only" && !start && "nextSibling";
							}
							return true;
						}

						start = [ forward ? parent.firstChild : parent.lastChild ];

						// non-xml :nth-child(...) stores cache data on `parent`
						if ( forward && useCache ) {

							// Seek `elem` from a previously-cached index

							// ...in a gzip-friendly way
							node = parent;
							outerCache = node[ expando ] || (node[ expando ] = {});

							// Support: IE <9 only
							// Defend against cloned attroperties (jQuery gh-1709)
							uniqueCache = outerCache[ node.uniqueID ] ||
								(outerCache[ node.uniqueID ] = {});

							cache = uniqueCache[ type ] || [];
							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
							diff = nodeIndex && cache[ 2 ];
							node = nodeIndex && parent.childNodes[ nodeIndex ];

							while ( (node = ++nodeIndex && node && node[ dir ] ||

								// Fallback to seeking `elem` from the start
								(diff = nodeIndex = 0) || start.pop()) ) {

								// When found, cache indexes on `parent` and break
								if ( node.nodeType === 1 && ++diff && node === elem ) {
									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
									break;
								}
							}

						} else {
							// Use previously-cached element index if available
							if ( useCache ) {
								// ...in a gzip-friendly way
								node = elem;
								outerCache = node[ expando ] || (node[ expando ] = {});

								// Support: IE <9 only
								// Defend against cloned attroperties (jQuery gh-1709)
								uniqueCache = outerCache[ node.uniqueID ] ||
									(outerCache[ node.uniqueID ] = {});

								cache = uniqueCache[ type ] || [];
								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
								diff = nodeIndex;
							}

							// xml :nth-child(...)
							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
							if ( diff === false ) {
								// Use the same loop as above to seek `elem` from the start
								while ( (node = ++nodeIndex && node && node[ dir ] ||
									(diff = nodeIndex = 0) || start.pop()) ) {

									if ( ( ofType ?
										node.nodeName.toLowerCase() === name :
										node.nodeType === 1 ) &&
										++diff ) {

										// Cache the index of each encountered element
										if ( useCache ) {
											outerCache = node[ expando ] || (node[ expando ] = {});

											// Support: IE <9 only
											// Defend against cloned attroperties (jQuery gh-1709)
											uniqueCache = outerCache[ node.uniqueID ] ||
												(outerCache[ node.uniqueID ] = {});

											uniqueCache[ type ] = [ dirruns, diff ];
										}

										if ( node === elem ) {
											break;
										}
									}
								}
							}
						}

						// Incorporate the offset, then check against cycle size
						diff -= last;
						return diff === first || ( diff % first === 0 && diff / first >= 0 );
					}
				};
		},

		"PSEUDO": function( pseudo, argument ) {
			// pseudo-class names are case-insensitive
			// http://www.w3.org/TR/selectors/#pseudo-classes
			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
			// Remember that setFilters inherits from pseudos
			var args,
				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
					Sizzle.error( "unsupported pseudo: " + pseudo );

			// The user may use createPseudo to indicate that
			// arguments are needed to create the filter function
			// just as Sizzle does
			if ( fn[ expando ] ) {
				return fn( argument );
			}

			// But maintain support for old signatures
			if ( fn.length > 1 ) {
				args = [ pseudo, pseudo, "", argument ];
				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
					markFunction(function( seed, matches ) {
						var idx,
							matched = fn( seed, argument ),
							i = matched.length;
						while ( i-- ) {
							idx = indexOf( seed, matched[i] );
							seed[ idx ] = !( matches[ idx ] = matched[i] );
						}
					}) :
					function( elem ) {
						return fn( elem, 0, args );
					};
			}

			return fn;
		}
	},

	pseudos: {
		// Potentially complex pseudos
		"not": markFunction(function( selector ) {
			// Trim the selector passed to compile
			// to avoid treating leading and trailing
			// spaces as combinators
			var input = [],
				results = [],
				matcher = compile( selector.replace( rtrim, "$1" ) );

			return matcher[ expando ] ?
				markFunction(function( seed, matches, context, xml ) {
					var elem,
						unmatched = matcher( seed, null, xml, [] ),
						i = seed.length;

					// Match elements unmatched by `matcher`
					while ( i-- ) {
						if ( (elem = unmatched[i]) ) {
							seed[i] = !(matches[i] = elem);
						}
					}
				}) :
				function( elem, context, xml ) {
					input[0] = elem;
					matcher( input, null, xml, results );
					// Don't keep the element (issue #299)
					input[0] = null;
					return !results.pop();
				};
		}),

		"has": markFunction(function( selector ) {
			return function( elem ) {
				return Sizzle( selector, elem ).length > 0;
			};
		}),

		"contains": markFunction(function( text ) {
			text = text.replace( runescape, funescape );
			return function( elem ) {
				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
			};
		}),

		// "Whether an element is represented by a :lang() selector
		// is based solely on the element's language value
		// being equal to the identifier C,
		// or beginning with the identifier C immediately followed by "-".
		// The matching of C against the element's language value is performed case-insensitively.
		// The identifier C does not have to be a valid language name."
		// http://www.w3.org/TR/selectors/#lang-pseudo
		"lang": markFunction( function( lang ) {
			// lang value must be a valid identifier
			if ( !ridentifier.test(lang || "") ) {
				Sizzle.error( "unsupported lang: " + lang );
			}
			lang = lang.replace( runescape, funescape ).toLowerCase();
			return function( elem ) {
				var elemLang;
				do {
					if ( (elemLang = documentIsHTML ?
						elem.lang :
						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {

						elemLang = elemLang.toLowerCase();
						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
					}
				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
				return false;
			};
		}),

		// Miscellaneous
		"target": function( elem ) {
			var hash = window.location && window.location.hash;
			return hash && hash.slice( 1 ) === elem.id;
		},

		"root": function( elem ) {
			return elem === docElem;
		},

		"focus": function( elem ) {
			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
		},

		// Boolean properties
		"enabled": function( elem ) {
			return elem.disabled === false;
		},

		"disabled": function( elem ) {
			return elem.disabled === true;
		},

		"checked": function( elem ) {
			// In CSS3, :checked should return both checked and selected elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			var nodeName = elem.nodeName.toLowerCase();
			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
		},

		"selected": function( elem ) {
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			if ( elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}

			return elem.selected === true;
		},

		// Contents
		"empty": function( elem ) {
			// http://www.w3.org/TR/selectors/#empty-pseudo
			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
			//   but not by others (comment: 8; processing instruction: 7; etc.)
			// nodeType < 6 works because attributes (2) do not appear as children
			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
				if ( elem.nodeType < 6 ) {
					return false;
				}
			}
			return true;
		},

		"parent": function( elem ) {
			return !Expr.pseudos["empty"]( elem );
		},

		// Element/input types
		"header": function( elem ) {
			return rheader.test( elem.nodeName );
		},

		"input": function( elem ) {
			return rinputs.test( elem.nodeName );
		},

		"button": function( elem ) {
			var name = elem.nodeName.toLowerCase();
			return name === "input" && elem.type === "button" || name === "button";
		},

		"text": function( elem ) {
			var attr;
			return elem.nodeName.toLowerCase() === "input" &&
				elem.type === "text" &&

				// Support: IE<8
				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
		},

		// Position-in-collection
		"first": createPositionalPseudo(function() {
			return [ 0 ];
		}),

		"last": createPositionalPseudo(function( matchIndexes, length ) {
			return [ length - 1 ];
		}),

		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
			return [ argument < 0 ? argument + length : argument ];
		}),

		"even": createPositionalPseudo(function( matchIndexes, length ) {
			var i = 0;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"odd": createPositionalPseudo(function( matchIndexes, length ) {
			var i = 1;
			for ( ; i < length; i += 2 ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
			var i = argument < 0 ? argument + length : argument;
			for ( ; --i >= 0; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),

		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
			var i = argument < 0 ? argument + length : argument;
			for ( ; ++i < length; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		})
	}
};

Expr.pseudos["nth"] = Expr.pseudos["eq"];

// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
	Expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
	Expr.pseudos[ i ] = createButtonPseudo( i );
}

// Easy API for creating new setFilters
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();

tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
	var matched, match, tokens, type,
		soFar, groups, preFilters,
		cached = tokenCache[ selector + " " ];

	if ( cached ) {
		return parseOnly ? 0 : cached.slice( 0 );
	}

	soFar = selector;
	groups = [];
	preFilters = Expr.preFilter;

	while ( soFar ) {

		// Comma and first run
		if ( !matched || (match = rcomma.exec( soFar )) ) {
			if ( match ) {
				// Don't consume trailing commas as valid
				soFar = soFar.slice( match[0].length ) || soFar;
			}
			groups.push( (tokens = []) );
		}

		matched = false;

		// Combinators
		if ( (match = rcombinators.exec( soFar )) ) {
			matched = match.shift();
			tokens.push({
				value: matched,
				// Cast descendant combinators to space
				type: match[0].replace( rtrim, " " )
			});
			soFar = soFar.slice( matched.length );
		}

		// Filters
		for ( type in Expr.filter ) {
			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
				(match = preFilters[ type ]( match ))) ) {
				matched = match.shift();
				tokens.push({
					value: matched,
					type: type,
					matches: match
				});
				soFar = soFar.slice( matched.length );
			}
		}

		if ( !matched ) {
			break;
		}
	}

	// Return the length of the invalid excess
	// if we're just parsing
	// Otherwise, throw an error or return tokens
	return parseOnly ?
		soFar.length :
		soFar ?
			Sizzle.error( selector ) :
			// Cache the tokens
			tokenCache( selector, groups ).slice( 0 );
};

function toSelector( tokens ) {
	var i = 0,
		len = tokens.length,
		selector = "";
	for ( ; i < len; i++ ) {
		selector += tokens[i].value;
	}
	return selector;
}

function addCombinator( matcher, combinator, base ) {
	var dir = combinator.dir,
		checkNonElements = base && dir === "parentNode",
		doneName = done++;

	return combinator.first ?
		// Check against closest ancestor/preceding element
		function( elem, context, xml ) {
			while ( (elem = elem[ dir ]) ) {
				if ( elem.nodeType === 1 || checkNonElements ) {
					return matcher( elem, context, xml );
				}
			}
		} :

		// Check against all ancestor/preceding elements
		function( elem, context, xml ) {
			var oldCache, uniqueCache, outerCache,
				newCache = [ dirruns, doneName ];

			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
			if ( xml ) {
				while ( (elem = elem[ dir ]) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						if ( matcher( elem, context, xml ) ) {
							return true;
						}
					}
				}
			} else {
				while ( (elem = elem[ dir ]) ) {
					if ( elem.nodeType === 1 || checkNonElements ) {
						outerCache = elem[ expando ] || (elem[ expando ] = {});

						// Support: IE <9 only
						// Defend against cloned attroperties (jQuery gh-1709)
						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});

						if ( (oldCache = uniqueCache[ dir ]) &&
							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {

							// Assign to newCache so results back-propagate to previous elements
							return (newCache[ 2 ] = oldCache[ 2 ]);
						} else {
							// Reuse newcache so results back-propagate to previous elements
							uniqueCache[ dir ] = newCache;

							// A match means we're done; a fail means we have to keep checking
							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
								return true;
							}
						}
					}
				}
			}
		};
}

function elementMatcher( matchers ) {
	return matchers.length > 1 ?
		function( elem, context, xml ) {
			var i = matchers.length;
			while ( i-- ) {
				if ( !matchers[i]( elem, context, xml ) ) {
					return false;
				}
			}
			return true;
		} :
		matchers[0];
}

function multipleContexts( selector, contexts, results ) {
	var i = 0,
		len = contexts.length;
	for ( ; i < len; i++ ) {
		Sizzle( selector, contexts[i], results );
	}
	return results;
}

function condense( unmatched, map, filter, context, xml ) {
	var elem,
		newUnmatched = [],
		i = 0,
		len = unmatched.length,
		mapped = map != null;

	for ( ; i < len; i++ ) {
		if ( (elem = unmatched[i]) ) {
			if ( !filter || filter( elem, context, xml ) ) {
				newUnmatched.push( elem );
				if ( mapped ) {
					map.push( i );
				}
			}
		}
	}

	return newUnmatched;
}

function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
	if ( postFilter && !postFilter[ expando ] ) {
		postFilter = setMatcher( postFilter );
	}
	if ( postFinder && !postFinder[ expando ] ) {
		postFinder = setMatcher( postFinder, postSelector );
	}
	return markFunction(function( seed, results, context, xml ) {
		var temp, i, elem,
			preMap = [],
			postMap = [],
			preexisting = results.length,

			// Get initial elements from seed or context
			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),

			// Prefilter to get matcher input, preserving a map for seed-results synchronization
			matcherIn = preFilter && ( seed || !selector ) ?
				condense( elems, preMap, preFilter, context, xml ) :
				elems,

			matcherOut = matcher ?
				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?

					// ...intermediate processing is necessary
					[] :

					// ...otherwise use results directly
					results :
				matcherIn;

		// Find primary matches
		if ( matcher ) {
			matcher( matcherIn, matcherOut, context, xml );
		}

		// Apply postFilter
		if ( postFilter ) {
			temp = condense( matcherOut, postMap );
			postFilter( temp, [], context, xml );

			// Un-match failing elements by moving them back to matcherIn
			i = temp.length;
			while ( i-- ) {
				if ( (elem = temp[i]) ) {
					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
				}
			}
		}

		if ( seed ) {
			if ( postFinder || preFilter ) {
				if ( postFinder ) {
					// Get the final matcherOut by condensing this intermediate into postFinder contexts
					temp = [];
					i = matcherOut.length;
					while ( i-- ) {
						if ( (elem = matcherOut[i]) ) {
							// Restore matcherIn since elem is not yet a final match
							temp.push( (matcherIn[i] = elem) );
						}
					}
					postFinder( null, (matcherOut = []), temp, xml );
				}

				// Move matched elements from seed to results to keep them synchronized
				i = matcherOut.length;
				while ( i-- ) {
					if ( (elem = matcherOut[i]) &&
						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {

						seed[temp] = !(results[temp] = elem);
					}
				}
			}

		// Add elements to results, through postFinder if defined
		} else {
			matcherOut = condense(
				matcherOut === results ?
					matcherOut.splice( preexisting, matcherOut.length ) :
					matcherOut
			);
			if ( postFinder ) {
				postFinder( null, results, matcherOut, xml );
			} else {
				push.apply( results, matcherOut );
			}
		}
	});
}

function matcherFromTokens( tokens ) {
	var checkContext, matcher, j,
		len = tokens.length,
		leadingRelative = Expr.relative[ tokens[0].type ],
		implicitRelative = leadingRelative || Expr.relative[" "],
		i = leadingRelative ? 1 : 0,

		// The foundational matcher ensures that elements are reachable from top-level context(s)
		matchContext = addCombinator( function( elem ) {
			return elem === checkContext;
		}, implicitRelative, true ),
		matchAnyContext = addCombinator( function( elem ) {
			return indexOf( checkContext, elem ) > -1;
		}, implicitRelative, true ),
		matchers = [ function( elem, context, xml ) {
			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
				(checkContext = context).nodeType ?
					matchContext( elem, context, xml ) :
					matchAnyContext( elem, context, xml ) );
			// Avoid hanging onto element (issue #299)
			checkContext = null;
			return ret;
		} ];

	for ( ; i < len; i++ ) {
		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
		} else {
			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );

			// Return special upon seeing a positional matcher
			if ( matcher[ expando ] ) {
				// Find the next relative operator (if any) for proper handling
				j = ++i;
				for ( ; j < len; j++ ) {
					if ( Expr.relative[ tokens[j].type ] ) {
						break;
					}
				}
				return setMatcher(
					i > 1 && elementMatcher( matchers ),
					i > 1 && toSelector(
						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
					).replace( rtrim, "$1" ),
					matcher,
					i < j && matcherFromTokens( tokens.slice( i, j ) ),
					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
					j < len && toSelector( tokens )
				);
			}
			matchers.push( matcher );
		}
	}

	return elementMatcher( matchers );
}

function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
	var bySet = setMatchers.length > 0,
		byElement = elementMatchers.length > 0,
		superMatcher = function( seed, context, xml, results, outermost ) {
			var elem, j, matcher,
				matchedCount = 0,
				i = "0",
				unmatched = seed && [],
				setMatched = [],
				contextBackup = outermostContext,
				// We must always have either seed elements or outermost context
				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
				// Use integer dirruns iff this is the outermost matcher
				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
				len = elems.length;

			if ( outermost ) {
				outermostContext = context === document || context || outermost;
			}

			// Add elements passing elementMatchers directly to results
			// Support: IE<9, Safari
			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
				if ( byElement && elem ) {
					j = 0;
					if ( !context && elem.ownerDocument !== document ) {
						setDocument( elem );
						xml = !documentIsHTML;
					}
					while ( (matcher = elementMatchers[j++]) ) {
						if ( matcher( elem, context || document, xml) ) {
							results.push( elem );
							break;
						}
					}
					if ( outermost ) {
						dirruns = dirrunsUnique;
					}
				}

				// Track unmatched elements for set filters
				if ( bySet ) {
					// They will have gone through all possible matchers
					if ( (elem = !matcher && elem) ) {
						matchedCount--;
					}

					// Lengthen the array for every element, matched or not
					if ( seed ) {
						unmatched.push( elem );
					}
				}
			}

			// `i` is now the count of elements visited above, and adding it to `matchedCount`
			// makes the latter nonnegative.
			matchedCount += i;

			// Apply set filters to unmatched elements
			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
			// no element matchers and no seed.
			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
			// numerically zero.
			if ( bySet && i !== matchedCount ) {
				j = 0;
				while ( (matcher = setMatchers[j++]) ) {
					matcher( unmatched, setMatched, context, xml );
				}

				if ( seed ) {
					// Reintegrate element matches to eliminate the need for sorting
					if ( matchedCount > 0 ) {
						while ( i-- ) {
							if ( !(unmatched[i] || setMatched[i]) ) {
								setMatched[i] = pop.call( results );
							}
						}
					}

					// Discard index placeholder values to get only actual matches
					setMatched = condense( setMatched );
				}

				// Add matches to results
				push.apply( results, setMatched );

				// Seedless set matches succeeding multiple successful matchers stipulate sorting
				if ( outermost && !seed && setMatched.length > 0 &&
					( matchedCount + setMatchers.length ) > 1 ) {

					Sizzle.uniqueSort( results );
				}
			}

			// Override manipulation of globals by nested matchers
			if ( outermost ) {
				dirruns = dirrunsUnique;
				outermostContext = contextBackup;
			}

			return unmatched;
		};

	return bySet ?
		markFunction( superMatcher ) :
		superMatcher;
}

compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
	var i,
		setMatchers = [],
		elementMatchers = [],
		cached = compilerCache[ selector + " " ];

	if ( !cached ) {
		// Generate a function of recursive functions that can be used to check each element
		if ( !match ) {
			match = tokenize( selector );
		}
		i = match.length;
		while ( i-- ) {
			cached = matcherFromTokens( match[i] );
			if ( cached[ expando ] ) {
				setMatchers.push( cached );
			} else {
				elementMatchers.push( cached );
			}
		}

		// Cache the compiled function
		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );

		// Save selector and tokenization
		cached.selector = selector;
	}
	return cached;
};

/**
 * A low-level selection function that works with Sizzle's compiled
 *  selector functions
 * @param {String|Function} selector A selector or a pre-compiled
 *  selector function built with Sizzle.compile
 * @param {Element} context
 * @param {Array} [results]
 * @param {Array} [seed] A set of elements to match against
 */
select = Sizzle.select = function( selector, context, results, seed ) {
	var i, tokens, token, type, find,
		compiled = typeof selector === "function" && selector,
		match = !seed && tokenize( (selector = compiled.selector || selector) );

	results = results || [];

	// Try to minimize operations if there is only one selector in the list and no seed
	// (the latter of which guarantees us context)
	if ( match.length === 1 ) {

		// Reduce context if the leading compound selector is an ID
		tokens = match[0] = match[0].slice( 0 );
		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
				support.getById && context.nodeType === 9 && documentIsHTML &&
				Expr.relative[ tokens[1].type ] ) {

			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
			if ( !context ) {
				return results;

			// Precompiled matchers will still verify ancestry, so step up a level
			} else if ( compiled ) {
				context = context.parentNode;
			}

			selector = selector.slice( tokens.shift().value.length );
		}

		// Fetch a seed set for right-to-left matching
		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
		while ( i-- ) {
			token = tokens[i];

			// Abort if we hit a combinator
			if ( Expr.relative[ (type = token.type) ] ) {
				break;
			}
			if ( (find = Expr.find[ type ]) ) {
				// Search, expanding context for leading sibling combinators
				if ( (seed = find(
					token.matches[0].replace( runescape, funescape ),
					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
				)) ) {

					// If seed is empty or no tokens remain, we can return early
					tokens.splice( i, 1 );
					selector = seed.length && toSelector( tokens );
					if ( !selector ) {
						push.apply( results, seed );
						return results;
					}

					break;
				}
			}
		}
	}

	// Compile and execute a filtering function if one is not provided
	// Provide `match` to avoid retokenization if we modified the selector above
	( compiled || compile( selector, match ) )(
		seed,
		context,
		!documentIsHTML,
		results,
		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
	);
	return results;
};

// One-time assignments

// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;

// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;

// Initialize against the default document
setDocument();

// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert(function( div1 ) {
	// Should return 1, but returns 4 (following)
	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
});

// Support: IE<8
// Prevent attribute/property "interpolation"
// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !assert(function( div ) {
	div.innerHTML = "<a href='#'></a>";
	return div.firstChild.getAttribute("href") === "#" ;
}) ) {
	addHandle( "type|href|height|width", function( elem, name, isXML ) {
		if ( !isXML ) {
			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
		}
	});
}

// Support: IE<9
// Use defaultValue in place of getAttribute("value")
if ( !support.attributes || !assert(function( div ) {
	div.innerHTML = "<input/>";
	div.firstChild.setAttribute( "value", "" );
	return div.firstChild.getAttribute( "value" ) === "";
}) ) {
	addHandle( "value", function( elem, name, isXML ) {
		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
			return elem.defaultValue;
		}
	});
}

// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
if ( !assert(function( div ) {
	return div.getAttribute("disabled") == null;
}) ) {
	addHandle( booleans, function( elem, name, isXML ) {
		var val;
		if ( !isXML ) {
			return elem[ name ] === true ? name.toLowerCase() :
					(val = elem.getAttributeNode( name )) && val.specified ?
					val.value :
				null;
		}
	});
}

return Sizzle;

})( window );



jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;



var dir = function( elem, dir, until ) {
	var matched = [],
		truncate = until !== undefined;

	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
		if ( elem.nodeType === 1 ) {
			if ( truncate && jQuery( elem ).is( until ) ) {
				break;
			}
			matched.push( elem );
		}
	}
	return matched;
};


var siblings = function( n, elem ) {
	var matched = [];

	for ( ; n; n = n.nextSibling ) {
		if ( n.nodeType === 1 && n !== elem ) {
			matched.push( n );
		}
	}

	return matched;
};


var rneedsContext = jQuery.expr.match.needsContext;

var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );



var risSimple = /^.[^:#\[\.,]*$/;

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep( elements, function( elem, i ) {
			/* jshint -W018 */
			return !!qualifier.call( elem, i, elem ) !== not;
		} );

	}

	if ( qualifier.nodeType ) {
		return jQuery.grep( elements, function( elem ) {
			return ( elem === qualifier ) !== not;
		} );

	}

	if ( typeof qualifier === "string" ) {
		if ( risSimple.test( qualifier ) ) {
			return jQuery.filter( qualifier, elements, not );
		}

		qualifier = jQuery.filter( qualifier, elements );
	}

	return jQuery.grep( elements, function( elem ) {
		return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
	} );
}

jQuery.filter = function( expr, elems, not ) {
	var elem = elems[ 0 ];

	if ( not ) {
		expr = ":not(" + expr + ")";
	}

	return elems.length === 1 && elem.nodeType === 1 ?
		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
			return elem.nodeType === 1;
		} ) );
};

jQuery.fn.extend( {
	find: function( selector ) {
		var i,
			len = this.length,
			ret = [],
			self = this;

		if ( typeof selector !== "string" ) {
			return this.pushStack( jQuery( selector ).filter( function() {
				for ( i = 0; i < len; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			} ) );
		}

		for ( i = 0; i < len; i++ ) {
			jQuery.find( selector, self[ i ], ret );
		}

		// Needed because $( selector, context ) becomes $( context ).find( selector )
		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
		ret.selector = this.selector ? this.selector + " " + selector : selector;
		return ret;
	},
	filter: function( selector ) {
		return this.pushStack( winnow( this, selector || [], false ) );
	},
	not: function( selector ) {
		return this.pushStack( winnow( this, selector || [], true ) );
	},
	is: function( selector ) {
		return !!winnow(
			this,

			// If this is a positional/relative selector, check membership in the returned set
			// so $("p:first").is("p:last") won't return true for a doc with two "p".
			typeof selector === "string" && rneedsContext.test( selector ) ?
				jQuery( selector ) :
				selector || [],
			false
		).length;
	}
} );


// Initialize a jQuery object


// A central reference to the root jQuery(document)
var rootjQuery,

	// A simple way to check for HTML strings
	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
	// Strict HTML recognition (#11290: must start with <)
	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

	init = jQuery.fn.init = function( selector, context, root ) {
		var match, elem;

		// HANDLE: $(""), $(null), $(undefined), $(false)
		if ( !selector ) {
			return this;
		}

		// Method init() accepts an alternate rootjQuery
		// so migrate can support jQuery.sub (gh-2101)
		root = root || rootjQuery;

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			if ( selector[ 0 ] === "<" &&
				selector[ selector.length - 1 ] === ">" &&
				selector.length >= 3 ) {

				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = rquickExpr.exec( selector );
			}

			// Match html or make sure no context is specified for #id
			if ( match && ( match[ 1 ] || !context ) ) {

				// HANDLE: $(html) -> $(array)
				if ( match[ 1 ] ) {
					context = context instanceof jQuery ? context[ 0 ] : context;

					// Option to run scripts is true for back-compat
					// Intentionally let the error be thrown if parseHTML is not present
					jQuery.merge( this, jQuery.parseHTML(
						match[ 1 ],
						context && context.nodeType ? context.ownerDocument || context : document,
						true
					) );

					// HANDLE: $(html, props)
					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
						for ( match in context ) {

							// Properties of context are called as methods if possible
							if ( jQuery.isFunction( this[ match ] ) ) {
								this[ match ]( context[ match ] );

							// ...and otherwise set as attributes
							} else {
								this.attr( match, context[ match ] );
							}
						}
					}

					return this;

				// HANDLE: $(#id)
				} else {
					elem = document.getElementById( match[ 2 ] );

					// Support: Blackberry 4.6
					// gEBID returns nodes no longer in the document (#6963)
					if ( elem && elem.parentNode ) {

						// Inject the element directly into the jQuery object
						this.length = 1;
						this[ 0 ] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
				return ( context || root ).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(DOMElement)
		} else if ( selector.nodeType ) {
			this.context = this[ 0 ] = selector;
			this.length = 1;
			return this;

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return root.ready !== undefined ?
				root.ready( selector ) :

				// Execute immediately if ready is not present
				selector( jQuery );
		}

		if ( selector.selector !== undefined ) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.makeArray( selector, this );
	};

// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

// Initialize central reference
rootjQuery = jQuery( document );


var rparentsprev = /^(?:parents|prev(?:Until|All))/,

	// Methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend( {
	has: function( target ) {
		var targets = jQuery( target, this ),
			l = targets.length;

		return this.filter( function() {
			var i = 0;
			for ( ; i < l; i++ ) {
				if ( jQuery.contains( this, targets[ i ] ) ) {
					return true;
				}
			}
		} );
	},

	closest: function( selectors, context ) {
		var cur,
			i = 0,
			l = this.length,
			matched = [],
			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( ; i < l; i++ ) {
			for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {

				// Always skip document fragments
				if ( cur.nodeType < 11 && ( pos ?
					pos.index( cur ) > -1 :

					// Don't pass non-elements to Sizzle
					cur.nodeType === 1 &&
						jQuery.find.matchesSelector( cur, selectors ) ) ) {

					matched.push( cur );
					break;
				}
			}
		}

		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
	},

	// Determine the position of an element within the set
	index: function( elem ) {

		// No argument, return index in parent
		if ( !elem ) {
			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
		}

		// Index in selector
		if ( typeof elem === "string" ) {
			return indexOf.call( jQuery( elem ), this[ 0 ] );
		}

		// Locate the position of the desired element
		return indexOf.call( this,

			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[ 0 ] : elem
		);
	},

	add: function( selector, context ) {
		return this.pushStack(
			jQuery.uniqueSort(
				jQuery.merge( this.get(), jQuery( selector, context ) )
			)
		);
	},

	addBack: function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	}
} );

function sibling( cur, dir ) {
	while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
	return cur;
}

jQuery.each( {
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return sibling( elem, "nextSibling" );
	},
	prev: function( elem ) {
		return sibling( elem, "previousSibling" );
	},
	nextAll: function( elem ) {
		return dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return siblings( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return siblings( elem.firstChild );
	},
	contents: function( elem ) {
		return elem.contentDocument || jQuery.merge( [], elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var matched = jQuery.map( this, fn, until );

		if ( name.slice( -5 ) !== "Until" ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			matched = jQuery.filter( selector, matched );
		}

		if ( this.length > 1 ) {

			// Remove duplicates
			if ( !guaranteedUnique[ name ] ) {
				jQuery.uniqueSort( matched );
			}

			// Reverse order for parents* and prev-derivatives
			if ( rparentsprev.test( name ) ) {
				matched.reverse();
			}
		}

		return this.pushStack( matched );
	};
} );
var rnotwhite = ( /\S+/g );



// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
	var object = {};
	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
		object[ flag ] = true;
	} );
	return object;
}

/*
 * Create a callback list using the following parameters:
 *
 *	options: an optional list of space-separated options that will change how
 *			the callback list behaves or a more traditional option object
 *
 * By default a callback list will act like an event callback list and can be
 * "fired" multiple times.
 *
 * Possible options:
 *
 *	once:			will ensure the callback list can only be fired once (like a Deferred)
 *
 *	memory:			will keep track of previous values and will call any callback added
 *					after the list has been fired right away with the latest "memorized"
 *					values (like a Deferred)
 *
 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
 *
 *	stopOnFalse:	interrupt callings when a callback returns false
 *
 */
jQuery.Callbacks = function( options ) {

	// Convert options from String-formatted to Object-formatted if needed
	// (we check in cache first)
	options = typeof options === "string" ?
		createOptions( options ) :
		jQuery.extend( {}, options );

	var // Flag to know if list is currently firing
		firing,

		// Last fire value for non-forgettable lists
		memory,

		// Flag to know if list was already fired
		fired,

		// Flag to prevent firing
		locked,

		// Actual callback list
		list = [],

		// Queue of execution data for repeatable lists
		queue = [],

		// Index of currently firing callback (modified by add/remove as needed)
		firingIndex = -1,

		// Fire callbacks
		fire = function() {

			// Enforce single-firing
			locked = options.once;

			// Execute callbacks for all pending executions,
			// respecting firingIndex overrides and runtime changes
			fired = firing = true;
			for ( ; queue.length; firingIndex = -1 ) {
				memory = queue.shift();
				while ( ++firingIndex < list.length ) {

					// Run callback and check for early termination
					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
						options.stopOnFalse ) {

						// Jump to end and forget the data so .add doesn't re-fire
						firingIndex = list.length;
						memory = false;
					}
				}
			}

			// Forget the data if we're done with it
			if ( !options.memory ) {
				memory = false;
			}

			firing = false;

			// Clean up if we're done firing for good
			if ( locked ) {

				// Keep an empty list if we have data for future add calls
				if ( memory ) {
					list = [];

				// Otherwise, this object is spent
				} else {
					list = "";
				}
			}
		},

		// Actual Callbacks object
		self = {

			// Add a callback or a collection of callbacks to the list
			add: function() {
				if ( list ) {

					// If we have memory from a past run, we should fire after adding
					if ( memory && !firing ) {
						firingIndex = list.length - 1;
						queue.push( memory );
					}

					( function add( args ) {
						jQuery.each( args, function( _, arg ) {
							if ( jQuery.isFunction( arg ) ) {
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {

								// Inspect recursively
								add( arg );
							}
						} );
					} )( arguments );

					if ( memory && !firing ) {
						fire();
					}
				}
				return this;
			},

			// Remove a callback from the list
			remove: function() {
				jQuery.each( arguments, function( _, arg ) {
					var index;
					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
						list.splice( index, 1 );

						// Handle firing indexes
						if ( index <= firingIndex ) {
							firingIndex--;
						}
					}
				} );
				return this;
			},

			// Check if a given callback is in the list.
			// If no argument is given, return whether or not list has callbacks attached.
			has: function( fn ) {
				return fn ?
					jQuery.inArray( fn, list ) > -1 :
					list.length > 0;
			},

			// Remove all callbacks from the list
			empty: function() {
				if ( list ) {
					list = [];
				}
				return this;
			},

			// Disable .fire and .add
			// Abort any current/pending executions
			// Clear all callbacks and values
			disable: function() {
				locked = queue = [];
				list = memory = "";
				return this;
			},
			disabled: function() {
				return !list;
			},

			// Disable .fire
			// Also disable .add unless we have memory (since it would have no effect)
			// Abort any pending executions
			lock: function() {
				locked = queue = [];
				if ( !memory ) {
					list = memory = "";
				}
				return this;
			},
			locked: function() {
				return !!locked;
			},

			// Call all callbacks with the given context and arguments
			fireWith: function( context, args ) {
				if ( !locked ) {
					args = args || [];
					args = [ context, args.slice ? args.slice() : args ];
					queue.push( args );
					if ( !firing ) {
						fire();
					}
				}
				return this;
			},

			// Call all the callbacks with the given arguments
			fire: function() {
				self.fireWith( this, arguments );
				return this;
			},

			// To know if the callbacks have already been called at least once
			fired: function() {
				return !!fired;
			}
		};

	return self;
};


jQuery.extend( {

	Deferred: function( func ) {
		var tuples = [

				// action, add listener, listener list, final state
				[ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ],
				[ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ],
				[ "notify", "progress", jQuery.Callbacks( "memory" ) ]
			],
			state = "pending",
			promise = {
				state: function() {
					return state;
				},
				always: function() {
					deferred.done( arguments ).fail( arguments );
					return this;
				},
				then: function( /* fnDone, fnFail, fnProgress */ ) {
					var fns = arguments;
					return jQuery.Deferred( function( newDefer ) {
						jQuery.each( tuples, function( i, tuple ) {
							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];

							// deferred[ done | fail | progress ] for forwarding actions to newDefer
							deferred[ tuple[ 1 ] ]( function() {
								var returned = fn && fn.apply( this, arguments );
								if ( returned && jQuery.isFunction( returned.promise ) ) {
									returned.promise()
										.progress( newDefer.notify )
										.done( newDefer.resolve )
										.fail( newDefer.reject );
								} else {
									newDefer[ tuple[ 0 ] + "With" ](
										this === promise ? newDefer.promise() : this,
										fn ? [ returned ] : arguments
									);
								}
							} );
						} );
						fns = null;
					} ).promise();
				},

				// Get a promise for this deferred
				// If obj is provided, the promise aspect is added to the object
				promise: function( obj ) {
					return obj != null ? jQuery.extend( obj, promise ) : promise;
				}
			},
			deferred = {};

		// Keep pipe for back-compat
		promise.pipe = promise.then;

		// Add list-specific methods
		jQuery.each( tuples, function( i, tuple ) {
			var list = tuple[ 2 ],
				stateString = tuple[ 3 ];

			// promise[ done | fail | progress ] = list.add
			promise[ tuple[ 1 ] ] = list.add;

			// Handle state
			if ( stateString ) {
				list.add( function() {

					// state = [ resolved | rejected ]
					state = stateString;

				// [ reject_list | resolve_list ].disable; progress_list.lock
				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
			}

			// deferred[ resolve | reject | notify ]
			deferred[ tuple[ 0 ] ] = function() {
				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );
				return this;
			};
			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
		} );

		// Make the deferred a promise
		promise.promise( deferred );

		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}

		// All done!
		return deferred;
	},

	// Deferred helper
	when: function( subordinate /* , ..., subordinateN */ ) {
		var i = 0,
			resolveValues = slice.call( arguments ),
			length = resolveValues.length,

			// the count of uncompleted subordinates
			remaining = length !== 1 ||
				( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

			// the master Deferred.
			// If resolveValues consist of only a single Deferred, just use that.
			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

			// Update function for both resolve and progress values
			updateFunc = function( i, contexts, values ) {
				return function( value ) {
					contexts[ i ] = this;
					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
					if ( values === progressValues ) {
						deferred.notifyWith( contexts, values );
					} else if ( !( --remaining ) ) {
						deferred.resolveWith( contexts, values );
					}
				};
			},

			progressValues, progressContexts, resolveContexts;

		// Add listeners to Deferred subordinates; treat others as resolved
		if ( length > 1 ) {
			progressValues = new Array( length );
			progressContexts = new Array( length );
			resolveContexts = new Array( length );
			for ( ; i < length; i++ ) {
				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
					resolveValues[ i ].promise()
						.progress( updateFunc( i, progressContexts, progressValues ) )
						.done( updateFunc( i, resolveContexts, resolveValues ) )
						.fail( deferred.reject );
				} else {
					--remaining;
				}
			}
		}

		// If we're not waiting on anything, resolve the master
		if ( !remaining ) {
			deferred.resolveWith( resolveContexts, resolveValues );
		}

		return deferred.promise();
	}
} );


// The deferred used on DOM ready
var readyList;

jQuery.fn.ready = function( fn ) {

	// Add the callback
	jQuery.ready.promise().done( fn );

	return this;
};

jQuery.extend( {

	// Is the DOM ready to be used? Set to true once it occurs.
	isReady: false,

	// A counter to track how many items to wait for before
	// the ready event fires. See #6781
	readyWait: 1,

	// Hold (or release) the ready event
	holdReady: function( hold ) {
		if ( hold ) {
			jQuery.readyWait++;
		} else {
			jQuery.ready( true );
		}
	},

	// Handle when the DOM is ready
	ready: function( wait ) {

		// Abort if there are pending holds or we're already ready
		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
			return;
		}

		// Remember that the DOM is ready
		jQuery.isReady = true;

		// If a normal DOM Ready event fired, decrement, and wait if need be
		if ( wait !== true && --jQuery.readyWait > 0 ) {
			return;
		}

		// If there are functions bound, to execute
		readyList.resolveWith( document, [ jQuery ] );

		// Trigger any bound ready events
		if ( jQuery.fn.triggerHandler ) {
			jQuery( document ).triggerHandler( "ready" );
			jQuery( document ).off( "ready" );
		}
	}
} );

/**
 * The ready event handler and self cleanup method
 */
function completed() {
	document.removeEventListener( "DOMContentLoaded", completed );
	window.removeEventListener( "load", completed );
	jQuery.ready();
}

jQuery.ready.promise = function( obj ) {
	if ( !readyList ) {

		readyList = jQuery.Deferred();

		// Catch cases where $(document).ready() is called
		// after the browser event has already occurred.
		// Support: IE9-10 only
		// Older IE sometimes signals "interactive" too soon
		if ( document.readyState === "complete" ||
			( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {

			// Handle it asynchronously to allow scripts the opportunity to delay ready
			window.setTimeout( jQuery.ready );

		} else {

			// Use the handy event callback
			document.addEventListener( "DOMContentLoaded", completed );

			// A fallback to window.onload, that will always work
			window.addEventListener( "load", completed );
		}
	}
	return readyList.promise( obj );
};

// Kick off the DOM ready check even if the user does not
jQuery.ready.promise();




// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
	var i = 0,
		len = elems.length,
		bulk = key == null;

	// Sets many values
	if ( jQuery.type( key ) === "object" ) {
		chainable = true;
		for ( i in key ) {
			access( elems, fn, i, key[ i ], true, emptyGet, raw );
		}

	// Sets one value
	} else if ( value !== undefined ) {
		chainable = true;

		if ( !jQuery.isFunction( value ) ) {
			raw = true;
		}

		if ( bulk ) {

			// Bulk operations run against the entire set
			if ( raw ) {
				fn.call( elems, value );
				fn = null;

			// ...except when executing function values
			} else {
				bulk = fn;
				fn = function( elem, key, value ) {
					return bulk.call( jQuery( elem ), value );
				};
			}
		}

		if ( fn ) {
			for ( ; i < len; i++ ) {
				fn(
					elems[ i ], key, raw ?
					value :
					value.call( elems[ i ], i, fn( elems[ i ], key ) )
				);
			}
		}
	}

	return chainable ?
		elems :

		// Gets
		bulk ?
			fn.call( elems ) :
			len ? fn( elems[ 0 ], key ) : emptyGet;
};
var acceptData = function( owner ) {

	// Accepts only:
	//  - Node
	//    - Node.ELEMENT_NODE
	//    - Node.DOCUMENT_NODE
	//  - Object
	//    - Any
	/* jshint -W018 */
	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
};




function Data() {
	this.expando = jQuery.expando + Data.uid++;
}

Data.uid = 1;

Data.prototype = {

	register: function( owner, initial ) {
		var value = initial || {};

		// If it is a node unlikely to be stringify-ed or looped over
		// use plain assignment
		if ( owner.nodeType ) {
			owner[ this.expando ] = value;

		// Otherwise secure it in a non-enumerable, non-writable property
		// configurability must be true to allow the property to be
		// deleted with the delete operator
		} else {
			Object.defineProperty( owner, this.expando, {
				value: value,
				writable: true,
				configurable: true
			} );
		}
		return owner[ this.expando ];
	},
	cache: function( owner ) {

		// We can accept data for non-element nodes in modern browsers,
		// but we should not, see #8335.
		// Always return an empty object.
		if ( !acceptData( owner ) ) {
			return {};
		}

		// Check if the owner object already has a cache
		var value = owner[ this.expando ];

		// If not, create one
		if ( !value ) {
			value = {};

			// We can accept data for non-element nodes in modern browsers,
			// but we should not, see #8335.
			// Always return an empty object.
			if ( acceptData( owner ) ) {

				// If it is a node unlikely to be stringify-ed or looped over
				// use plain assignment
				if ( owner.nodeType ) {
					owner[ this.expando ] = value;

				// Otherwise secure it in a non-enumerable property
				// configurable must be true to allow the property to be
				// deleted when data is removed
				} else {
					Object.defineProperty( owner, this.expando, {
						value: value,
						configurable: true
					} );
				}
			}
		}

		return value;
	},
	set: function( owner, data, value ) {
		var prop,
			cache = this.cache( owner );

		// Handle: [ owner, key, value ] args
		if ( typeof data === "string" ) {
			cache[ data ] = value;

		// Handle: [ owner, { properties } ] args
		} else {

			// Copy the properties one-by-one to the cache object
			for ( prop in data ) {
				cache[ prop ] = data[ prop ];
			}
		}
		return cache;
	},
	get: function( owner, key ) {
		return key === undefined ?
			this.cache( owner ) :
			owner[ this.expando ] && owner[ this.expando ][ key ];
	},
	access: function( owner, key, value ) {
		var stored;

		// In cases where either:
		//
		//   1. No key was specified
		//   2. A string key was specified, but no value provided
		//
		// Take the "read" path and allow the get method to determine
		// which value to return, respectively either:
		//
		//   1. The entire cache object
		//   2. The data stored at the key
		//
		if ( key === undefined ||
				( ( key && typeof key === "string" ) && value === undefined ) ) {

			stored = this.get( owner, key );

			return stored !== undefined ?
				stored : this.get( owner, jQuery.camelCase( key ) );
		}

		// When the key is not a string, or both a key and value
		// are specified, set or extend (existing objects) with either:
		//
		//   1. An object of properties
		//   2. A key and value
		//
		this.set( owner, key, value );

		// Since the "set" path can have two possible entry points
		// return the expected data based on which path was taken[*]
		return value !== undefined ? value : key;
	},
	remove: function( owner, key ) {
		var i, name, camel,
			cache = owner[ this.expando ];

		if ( cache === undefined ) {
			return;
		}

		if ( key === undefined ) {
			this.register( owner );

		} else {

			// Support array or space separated string of keys
			if ( jQuery.isArray( key ) ) {

				// If "name" is an array of keys...
				// When data is initially created, via ("key", "val") signature,
				// keys will be converted to camelCase.
				// Since there is no way to tell _how_ a key was added, remove
				// both plain key and camelCase key. #12786
				// This will only penalize the array argument path.
				name = key.concat( key.map( jQuery.camelCase ) );
			} else {
				camel = jQuery.camelCase( key );

				// Try the string as a key before any manipulation
				if ( key in cache ) {
					name = [ key, camel ];
				} else {

					// If a key with the spaces exists, use it.
					// Otherwise, create an array by matching non-whitespace
					name = camel;
					name = name in cache ?
						[ name ] : ( name.match( rnotwhite ) || [] );
				}
			}

			i = name.length;

			while ( i-- ) {
				delete cache[ name[ i ] ];
			}
		}

		// Remove the expando if there's no more data
		if ( key === undefined || jQuery.isEmptyObject( cache ) ) {

			// Support: Chrome <= 35-45+
			// Webkit & Blink performance suffers when deleting properties
			// from DOM nodes, so set to undefined instead
			// https://code.google.com/p/chromium/issues/detail?id=378607
			if ( owner.nodeType ) {
				owner[ this.expando ] = undefined;
			} else {
				delete owner[ this.expando ];
			}
		}
	},
	hasData: function( owner ) {
		var cache = owner[ this.expando ];
		return cache !== undefined && !jQuery.isEmptyObject( cache );
	}
};
var dataPriv = new Data();

var dataUser = new Data();



//	Implementation Summary
//
//	1. Enforce API surface and semantic compatibility with 1.9.x branch
//	2. Improve the module's maintainability by reducing the storage
//		paths to a single mechanism.
//	3. Use the same single mechanism to support "private" and "user" data.
//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
//	5. Avoid exposing implementation details on user objects (eg. expando properties)
//	6. Provide a clear path for implementation upgrade to WeakMap in 2014

var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
	rmultiDash = /[A-Z]/g;

function dataAttr( elem, key, data ) {
	var name;

	// If nothing was found internally, try to fetch any
	// data from the HTML5 data-* attribute
	if ( data === undefined && elem.nodeType === 1 ) {
		name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
		data = elem.getAttribute( name );

		if ( typeof data === "string" ) {
			try {
				data = data === "true" ? true :
					data === "false" ? false :
					data === "null" ? null :

					// Only convert to a number if it doesn't change the string
					+data + "" === data ? +data :
					rbrace.test( data ) ? jQuery.parseJSON( data ) :
					data;
			} catch ( e ) {}

			// Make sure we set the data so it isn't changed later
			dataUser.set( elem, key, data );
		} else {
			data = undefined;
		}
	}
	return data;
}

jQuery.extend( {
	hasData: function( elem ) {
		return dataUser.hasData( elem ) || dataPriv.hasData( elem );
	},

	data: function( elem, name, data ) {
		return dataUser.access( elem, name, data );
	},

	removeData: function( elem, name ) {
		dataUser.remove( elem, name );
	},

	// TODO: Now that all calls to _data and _removeData have been replaced
	// with direct calls to dataPriv methods, these can be deprecated.
	_data: function( elem, name, data ) {
		return dataPriv.access( elem, name, data );
	},

	_removeData: function( elem, name ) {
		dataPriv.remove( elem, name );
	}
} );

jQuery.fn.extend( {
	data: function( key, value ) {
		var i, name, data,
			elem = this[ 0 ],
			attrs = elem && elem.attributes;

		// Gets all values
		if ( key === undefined ) {
			if ( this.length ) {
				data = dataUser.get( elem );

				if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
					i = attrs.length;
					while ( i-- ) {

						// Support: IE11+
						// The attrs elements can be null (#14894)
						if ( attrs[ i ] ) {
							name = attrs[ i ].name;
							if ( name.indexOf( "data-" ) === 0 ) {
								name = jQuery.camelCase( name.slice( 5 ) );
								dataAttr( elem, name, data[ name ] );
							}
						}
					}
					dataPriv.set( elem, "hasDataAttrs", true );
				}
			}

			return data;
		}

		// Sets multiple values
		if ( typeof key === "object" ) {
			return this.each( function() {
				dataUser.set( this, key );
			} );
		}

		return access( this, function( value ) {
			var data, camelKey;

			// The calling jQuery object (element matches) is not empty
			// (and therefore has an element appears at this[ 0 ]) and the
			// `value` parameter was not undefined. An empty jQuery object
			// will result in `undefined` for elem = this[ 0 ] which will
			// throw an exception if an attempt to read a data cache is made.
			if ( elem && value === undefined ) {

				// Attempt to get data from the cache
				// with the key as-is
				data = dataUser.get( elem, key ) ||

					// Try to find dashed key if it exists (gh-2779)
					// This is for 2.2.x only
					dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() );

				if ( data !== undefined ) {
					return data;
				}

				camelKey = jQuery.camelCase( key );

				// Attempt to get data from the cache
				// with the key camelized
				data = dataUser.get( elem, camelKey );
				if ( data !== undefined ) {
					return data;
				}

				// Attempt to "discover" the data in
				// HTML5 custom data-* attrs
				data = dataAttr( elem, camelKey, undefined );
				if ( data !== undefined ) {
					return data;
				}

				// We tried really hard, but the data doesn't exist.
				return;
			}

			// Set the data...
			camelKey = jQuery.camelCase( key );
			this.each( function() {

				// First, attempt to store a copy or reference of any
				// data that might've been store with a camelCased key.
				var data = dataUser.get( this, camelKey );

				// For HTML5 data-* attribute interop, we have to
				// store property names with dashes in a camelCase form.
				// This might not apply to all properties...*
				dataUser.set( this, camelKey, value );

				// *... In the case of properties that might _actually_
				// have dashes, we need to also store a copy of that
				// unchanged property.
				if ( key.indexOf( "-" ) > -1 && data !== undefined ) {
					dataUser.set( this, key, value );
				}
			} );
		}, null, value, arguments.length > 1, null, true );
	},

	removeData: function( key ) {
		return this.each( function() {
			dataUser.remove( this, key );
		} );
	}
} );


jQuery.extend( {
	queue: function( elem, type, data ) {
		var queue;

		if ( elem ) {
			type = ( type || "fx" ) + "queue";
			queue = dataPriv.get( elem, type );

			// Speed up dequeue by getting out quickly if this is just a lookup
			if ( data ) {
				if ( !queue || jQuery.isArray( data ) ) {
					queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
				} else {
					queue.push( data );
				}
			}
			return queue || [];
		}
	},

	dequeue: function( elem, type ) {
		type = type || "fx";

		var queue = jQuery.queue( elem, type ),
			startLength = queue.length,
			fn = queue.shift(),
			hooks = jQuery._queueHooks( elem, type ),
			next = function() {
				jQuery.dequeue( elem, type );
			};

		// If the fx queue is dequeued, always remove the progress sentinel
		if ( fn === "inprogress" ) {
			fn = queue.shift();
			startLength--;
		}

		if ( fn ) {

			// Add a progress sentinel to prevent the fx queue from being
			// automatically dequeued
			if ( type === "fx" ) {
				queue.unshift( "inprogress" );
			}

			// Clear up the last queue stop function
			delete hooks.stop;
			fn.call( elem, next, hooks );
		}

		if ( !startLength && hooks ) {
			hooks.empty.fire();
		}
	},

	// Not public - generate a queueHooks object, or return the current one
	_queueHooks: function( elem, type ) {
		var key = type + "queueHooks";
		return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
			empty: jQuery.Callbacks( "once memory" ).add( function() {
				dataPriv.remove( elem, [ type + "queue", key ] );
			} )
		} );
	}
} );

jQuery.fn.extend( {
	queue: function( type, data ) {
		var setter = 2;

		if ( typeof type !== "string" ) {
			data = type;
			type = "fx";
			setter--;
		}

		if ( arguments.length < setter ) {
			return jQuery.queue( this[ 0 ], type );
		}

		return data === undefined ?
			this :
			this.each( function() {
				var queue = jQuery.queue( this, type, data );

				// Ensure a hooks for this queue
				jQuery._queueHooks( this, type );

				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
					jQuery.dequeue( this, type );
				}
			} );
	},
	dequeue: function( type ) {
		return this.each( function() {
			jQuery.dequeue( this, type );
		} );
	},
	clearQueue: function( type ) {
		return this.queue( type || "fx", [] );
	},

	// Get a promise resolved when queues of a certain type
	// are emptied (fx is the type by default)
	promise: function( type, obj ) {
		var tmp,
			count = 1,
			defer = jQuery.Deferred(),
			elements = this,
			i = this.length,
			resolve = function() {
				if ( !( --count ) ) {
					defer.resolveWith( elements, [ elements ] );
				}
			};

		if ( typeof type !== "string" ) {
			obj = type;
			type = undefined;
		}
		type = type || "fx";

		while ( i-- ) {
			tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
			if ( tmp && tmp.empty ) {
				count++;
				tmp.empty.add( resolve );
			}
		}
		resolve();
		return defer.promise( obj );
	}
} );
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;

var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );


var cssExpand = [ "Top", "Right", "Bottom", "Left" ];

var isHidden = function( elem, el ) {

		// isHidden might be called from jQuery#filter function;
		// in that case, element will be second argument
		elem = el || elem;
		return jQuery.css( elem, "display" ) === "none" ||
			!jQuery.contains( elem.ownerDocument, elem );
	};



function adjustCSS( elem, prop, valueParts, tween ) {
	var adjusted,
		scale = 1,
		maxIterations = 20,
		currentValue = tween ?
			function() { return tween.cur(); } :
			function() { return jQuery.css( elem, prop, "" ); },
		initial = currentValue(),
		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),

		// Starting value computation is required for potential unit mismatches
		initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
			rcssNum.exec( jQuery.css( elem, prop ) );

	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {

		// Trust units reported by jQuery.css
		unit = unit || initialInUnit[ 3 ];

		// Make sure we update the tween properties later on
		valueParts = valueParts || [];

		// Iteratively approximate from a nonzero starting point
		initialInUnit = +initial || 1;

		do {

			// If previous iteration zeroed out, double until we get *something*.
			// Use string for doubling so we don't accidentally see scale as unchanged below
			scale = scale || ".5";

			// Adjust and apply
			initialInUnit = initialInUnit / scale;
			jQuery.style( elem, prop, initialInUnit + unit );

		// Update scale, tolerating zero or NaN from tween.cur()
		// Break the loop if scale is unchanged or perfect, or if we've just had enough.
		} while (
			scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
		);
	}

	if ( valueParts ) {
		initialInUnit = +initialInUnit || +initial || 0;

		// Apply relative offset (+=/-=) if specified
		adjusted = valueParts[ 1 ] ?
			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
			+valueParts[ 2 ];
		if ( tween ) {
			tween.unit = unit;
			tween.start = initialInUnit;
			tween.end = adjusted;
		}
	}
	return adjusted;
}
var rcheckableType = ( /^(?:checkbox|radio)$/i );

var rtagName = ( /<([\w:-]+)/ );

var rscriptType = ( /^$|\/(?:java|ecma)script/i );



// We have to close these tags to support XHTML (#13200)
var wrapMap = {

	// Support: IE9
	option: [ 1, "<select multiple='multiple'>", "</select>" ],

	// XHTML parsers do not magically insert elements in the
	// same way that tag soup parsers do. So we cannot shorten
	// this by omitting <tbody> or other required elements.
	thead: [ 1, "<table>", "</table>" ],
	col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],

	_default: [ 0, "", "" ]
};

// Support: IE9
wrapMap.optgroup = wrapMap.option;

wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;


function getAll( context, tag ) {

	// Support: IE9-11+
	// Use typeof to avoid zero-argument method invocation on host objects (#15151)
	var ret = typeof context.getElementsByTagName !== "undefined" ?
			context.getElementsByTagName( tag || "*" ) :
			typeof context.querySelectorAll !== "undefined" ?
				context.querySelectorAll( tag || "*" ) :
			[];

	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
		jQuery.merge( [ context ], ret ) :
		ret;
}


// Mark scripts as having already been evaluated
function setGlobalEval( elems, refElements ) {
	var i = 0,
		l = elems.length;

	for ( ; i < l; i++ ) {
		dataPriv.set(
			elems[ i ],
			"globalEval",
			!refElements || dataPriv.get( refElements[ i ], "globalEval" )
		);
	}
}


var rhtml = /<|&#?\w+;/;

function buildFragment( elems, context, scripts, selection, ignored ) {
	var elem, tmp, tag, wrap, contains, j,
		fragment = context.createDocumentFragment(),
		nodes = [],
		i = 0,
		l = elems.length;

	for ( ; i < l; i++ ) {
		elem = elems[ i ];

		if ( elem || elem === 0 ) {

			// Add nodes directly
			if ( jQuery.type( elem ) === "object" ) {

				// Support: Android<4.1, PhantomJS<2
				// push.apply(_, arraylike) throws on ancient WebKit
				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );

			// Convert non-html into a text node
			} else if ( !rhtml.test( elem ) ) {
				nodes.push( context.createTextNode( elem ) );

			// Convert html into DOM nodes
			} else {
				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );

				// Deserialize a standard representation
				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
				wrap = wrapMap[ tag ] || wrapMap._default;
				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

				// Descend through wrappers to the right content
				j = wrap[ 0 ];
				while ( j-- ) {
					tmp = tmp.lastChild;
				}

				// Support: Android<4.1, PhantomJS<2
				// push.apply(_, arraylike) throws on ancient WebKit
				jQuery.merge( nodes, tmp.childNodes );

				// Remember the top-level container
				tmp = fragment.firstChild;

				// Ensure the created nodes are orphaned (#12392)
				tmp.textContent = "";
			}
		}
	}

	// Remove wrapper from fragment
	fragment.textContent = "";

	i = 0;
	while ( ( elem = nodes[ i++ ] ) ) {

		// Skip elements already in the context collection (trac-4087)
		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
			if ( ignored ) {
				ignored.push( elem );
			}
			continue;
		}

		contains = jQuery.contains( elem.ownerDocument, elem );

		// Append to fragment
		tmp = getAll( fragment.appendChild( elem ), "script" );

		// Preserve script evaluation history
		if ( contains ) {
			setGlobalEval( tmp );
		}

		// Capture executables
		if ( scripts ) {
			j = 0;
			while ( ( elem = tmp[ j++ ] ) ) {
				if ( rscriptType.test( elem.type || "" ) ) {
					scripts.push( elem );
				}
			}
		}
	}

	return fragment;
}


( function() {
	var fragment = document.createDocumentFragment(),
		div = fragment.appendChild( document.createElement( "div" ) ),
		input = document.createElement( "input" );

	// Support: Android 4.0-4.3, Safari<=5.1
	// Check state lost if the name is set (#11217)
	// Support: Windows Web Apps (WWA)
	// `name` and `type` must use .setAttribute for WWA (#14901)
	input.setAttribute( "type", "radio" );
	input.setAttribute( "checked", "checked" );
	input.setAttribute( "name", "t" );

	div.appendChild( input );

	// Support: Safari<=5.1, Android<4.2
	// Older WebKit doesn't clone checked state correctly in fragments
	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

	// Support: IE<=11+
	// Make sure textarea (and checkbox) defaultValue is properly cloned
	div.innerHTML = "<textarea>x</textarea>";
	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
} )();


var
	rkeyEvent = /^key/,
	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
	rtypenamespace = /^([^.]*)(?:\.(.+)|)/;

function returnTrue() {
	return true;
}

function returnFalse() {
	return false;
}

// Support: IE9
// See #13393 for more info
function safeActiveElement() {
	try {
		return document.activeElement;
	} catch ( err ) { }
}

function on( elem, types, selector, data, fn, one ) {
	var origFn, type;

	// Types can be a map of types/handlers
	if ( typeof types === "object" ) {

		// ( types-Object, selector, data )
		if ( typeof selector !== "string" ) {

			// ( types-Object, data )
			data = data || selector;
			selector = undefined;
		}
		for ( type in types ) {
			on( elem, type, selector, data, types[ type ], one );
		}
		return elem;
	}

	if ( data == null && fn == null ) {

		// ( types, fn )
		fn = selector;
		data = selector = undefined;
	} else if ( fn == null ) {
		if ( typeof selector === "string" ) {

			// ( types, selector, fn )
			fn = data;
			data = undefined;
		} else {

			// ( types, data, fn )
			fn = data;
			data = selector;
			selector = undefined;
		}
	}
	if ( fn === false ) {
		fn = returnFalse;
	} else if ( !fn ) {
		return elem;
	}

	if ( one === 1 ) {
		origFn = fn;
		fn = function( event ) {

			// Can use an empty set, since event contains the info
			jQuery().off( event );
			return origFn.apply( this, arguments );
		};

		// Use same guid so caller can remove using origFn
		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
	}
	return elem.each( function() {
		jQuery.event.add( this, types, fn, data, selector );
	} );
}

/*
 * Helper functions for managing events -- not part of the public interface.
 * Props to Dean Edwards' addEvent library for many of the ideas.
 */
jQuery.event = {

	global: {},

	add: function( elem, types, handler, data, selector ) {

		var handleObjIn, eventHandle, tmp,
			events, t, handleObj,
			special, handlers, type, namespaces, origType,
			elemData = dataPriv.get( elem );

		// Don't attach events to noData or text/comment nodes (but allow plain objects)
		if ( !elemData ) {
			return;
		}

		// Caller can pass in an object of custom data in lieu of the handler
		if ( handler.handler ) {
			handleObjIn = handler;
			handler = handleObjIn.handler;
			selector = handleObjIn.selector;
		}

		// Make sure that the handler has a unique ID, used to find/remove it later
		if ( !handler.guid ) {
			handler.guid = jQuery.guid++;
		}

		// Init the element's event structure and main handler, if this is the first
		if ( !( events = elemData.events ) ) {
			events = elemData.events = {};
		}
		if ( !( eventHandle = elemData.handle ) ) {
			eventHandle = elemData.handle = function( e ) {

				// Discard the second event of a jQuery.event.trigger() and
				// when an event is called after a page has unloaded
				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
			};
		}

		// Handle multiple events separated by a space
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// There *must* be a type, no attaching namespace-only handlers
			if ( !type ) {
				continue;
			}

			// If event changes its type, use the special event handlers for the changed type
			special = jQuery.event.special[ type ] || {};

			// If selector defined, determine special event api type, otherwise given type
			type = ( selector ? special.delegateType : special.bindType ) || type;

			// Update special based on newly reset type
			special = jQuery.event.special[ type ] || {};

			// handleObj is passed to all event handlers
			handleObj = jQuery.extend( {
				type: type,
				origType: origType,
				data: data,
				handler: handler,
				guid: handler.guid,
				selector: selector,
				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
				namespace: namespaces.join( "." )
			}, handleObjIn );

			// Init the event handler queue if we're the first
			if ( !( handlers = events[ type ] ) ) {
				handlers = events[ type ] = [];
				handlers.delegateCount = 0;

				// Only use addEventListener if the special events handler returns false
				if ( !special.setup ||
					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {

					if ( elem.addEventListener ) {
						elem.addEventListener( type, eventHandle );
					}
				}
			}

			if ( special.add ) {
				special.add.call( elem, handleObj );

				if ( !handleObj.handler.guid ) {
					handleObj.handler.guid = handler.guid;
				}
			}

			// Add to the element's handler list, delegates in front
			if ( selector ) {
				handlers.splice( handlers.delegateCount++, 0, handleObj );
			} else {
				handlers.push( handleObj );
			}

			// Keep track of which events have ever been used, for event optimization
			jQuery.event.global[ type ] = true;
		}

	},

	// Detach an event or set of events from an element
	remove: function( elem, types, handler, selector, mappedTypes ) {

		var j, origCount, tmp,
			events, t, handleObj,
			special, handlers, type, namespaces, origType,
			elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );

		if ( !elemData || !( events = elemData.events ) ) {
			return;
		}

		// Once for each type.namespace in types; type may be omitted
		types = ( types || "" ).match( rnotwhite ) || [ "" ];
		t = types.length;
		while ( t-- ) {
			tmp = rtypenamespace.exec( types[ t ] ) || [];
			type = origType = tmp[ 1 ];
			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();

			// Unbind all events (on this namespace, if provided) for the element
			if ( !type ) {
				for ( type in events ) {
					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
				}
				continue;
			}

			special = jQuery.event.special[ type ] || {};
			type = ( selector ? special.delegateType : special.bindType ) || type;
			handlers = events[ type ] || [];
			tmp = tmp[ 2 ] &&
				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );

			// Remove matching events
			origCount = j = handlers.length;
			while ( j-- ) {
				handleObj = handlers[ j ];

				if ( ( mappedTypes || origType === handleObj.origType ) &&
					( !handler || handler.guid === handleObj.guid ) &&
					( !tmp || tmp.test( handleObj.namespace ) ) &&
					( !selector || selector === handleObj.selector ||
						selector === "**" && handleObj.selector ) ) {
					handlers.splice( j, 1 );

					if ( handleObj.selector ) {
						handlers.delegateCount--;
					}
					if ( special.remove ) {
						special.remove.call( elem, handleObj );
					}
				}
			}

			// Remove generic event handler if we removed something and no more handlers exist
			// (avoids potential for endless recursion during removal of special event handlers)
			if ( origCount && !handlers.length ) {
				if ( !special.teardown ||
					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {

					jQuery.removeEvent( elem, type, elemData.handle );
				}

				delete events[ type ];
			}
		}

		// Remove data and the expando if it's no longer used
		if ( jQuery.isEmptyObject( events ) ) {
			dataPriv.remove( elem, "handle events" );
		}
	},

	dispatch: function( event ) {

		// Make a writable jQuery.Event from the native event object
		event = jQuery.event.fix( event );

		var i, j, ret, matched, handleObj,
			handlerQueue = [],
			args = slice.call( arguments ),
			handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
			special = jQuery.event.special[ event.type ] || {};

		// Use the fix-ed jQuery.Event rather than the (read-only) native event
		args[ 0 ] = event;
		event.delegateTarget = this;

		// Call the preDispatch hook for the mapped type, and let it bail if desired
		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
			return;
		}

		// Determine handlers
		handlerQueue = jQuery.event.handlers.call( this, event, handlers );

		// Run delegates first; they may want to stop propagation beneath us
		i = 0;
		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
			event.currentTarget = matched.elem;

			j = 0;
			while ( ( handleObj = matched.handlers[ j++ ] ) &&
				!event.isImmediatePropagationStopped() ) {

				// Triggered event must either 1) have no namespace, or 2) have namespace(s)
				// a subset or equal to those in the bound event (both can have no namespace).
				if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {

					event.handleObj = handleObj;
					event.data = handleObj.data;

					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
						handleObj.handler ).apply( matched.elem, args );

					if ( ret !== undefined ) {
						if ( ( event.result = ret ) === false ) {
							event.preventDefault();
							event.stopPropagation();
						}
					}
				}
			}
		}

		// Call the postDispatch hook for the mapped type
		if ( special.postDispatch ) {
			special.postDispatch.call( this, event );
		}

		return event.result;
	},

	handlers: function( event, handlers ) {
		var i, matches, sel, handleObj,
			handlerQueue = [],
			delegateCount = handlers.delegateCount,
			cur = event.target;

		// Support (at least): Chrome, IE9
		// Find delegate handlers
		// Black-hole SVG <use> instance trees (#13180)
		//
		// Support: Firefox<=42+
		// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
		if ( delegateCount && cur.nodeType &&
			( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {

			for ( ; cur !== this; cur = cur.parentNode || this ) {

				// Don't check non-elements (#13208)
				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
				if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
					matches = [];
					for ( i = 0; i < delegateCount; i++ ) {
						handleObj = handlers[ i ];

						// Don't conflict with Object.prototype properties (#13203)
						sel = handleObj.selector + " ";

						if ( matches[ sel ] === undefined ) {
							matches[ sel ] = handleObj.needsContext ?
								jQuery( sel, this ).index( cur ) > -1 :
								jQuery.find( sel, this, null, [ cur ] ).length;
						}
						if ( matches[ sel ] ) {
							matches.push( handleObj );
						}
					}
					if ( matches.length ) {
						handlerQueue.push( { elem: cur, handlers: matches } );
					}
				}
			}
		}

		// Add the remaining (directly-bound) handlers
		if ( delegateCount < handlers.length ) {
			handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
		}

		return handlerQueue;
	},

	// Includes some event props shared by KeyEvent and MouseEvent
	props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " +
		"metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ),

	fixHooks: {},

	keyHooks: {
		props: "char charCode key keyCode".split( " " ),
		filter: function( event, original ) {

			// Add which for key events
			if ( event.which == null ) {
				event.which = original.charCode != null ? original.charCode : original.keyCode;
			}

			return event;
		}
	},

	mouseHooks: {
		props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " +
			"screenX screenY toElement" ).split( " " ),
		filter: function( event, original ) {
			var eventDoc, doc, body,
				button = original.button;

			// Calculate pageX/Y if missing and clientX/Y available
			if ( event.pageX == null && original.clientX != null ) {
				eventDoc = event.target.ownerDocument || document;
				doc = eventDoc.documentElement;
				body = eventDoc.body;

				event.pageX = original.clientX +
					( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
					( doc && doc.clientLeft || body && body.clientLeft || 0 );
				event.pageY = original.clientY +
					( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -
					( doc && doc.clientTop  || body && body.clientTop  || 0 );
			}

			// Add which for click: 1 === left; 2 === middle; 3 === right
			// Note: button is not normalized, so don't use it
			if ( !event.which && button !== undefined ) {
				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
			}

			return event;
		}
	},

	fix: function( event ) {
		if ( event[ jQuery.expando ] ) {
			return event;
		}

		// Create a writable copy of the event object and normalize some properties
		var i, prop, copy,
			type = event.type,
			originalEvent = event,
			fixHook = this.fixHooks[ type ];

		if ( !fixHook ) {
			this.fixHooks[ type ] = fixHook =
				rmouseEvent.test( type ) ? this.mouseHooks :
				rkeyEvent.test( type ) ? this.keyHooks :
				{};
		}
		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;

		event = new jQuery.Event( originalEvent );

		i = copy.length;
		while ( i-- ) {
			prop = copy[ i ];
			event[ prop ] = originalEvent[ prop ];
		}

		// Support: Cordova 2.5 (WebKit) (#13255)
		// All events should have a target; Cordova deviceready doesn't
		if ( !event.target ) {
			event.target = document;
		}

		// Support: Safari 6.0+, Chrome<28
		// Target should not be a text node (#504, #13143)
		if ( event.target.nodeType === 3 ) {
			event.target = event.target.parentNode;
		}

		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
	},

	special: {
		load: {

			// Prevent triggered image.load events from bubbling to window.load
			noBubble: true
		},
		focus: {

			// Fire native event if possible so blur/focus sequence is correct
			trigger: function() {
				if ( this !== safeActiveElement() && this.focus ) {
					this.focus();
					return false;
				}
			},
			delegateType: "focusin"
		},
		blur: {
			trigger: function() {
				if ( this === safeActiveElement() && this.blur ) {
					this.blur();
					return false;
				}
			},
			delegateType: "focusout"
		},
		click: {

			// For checkbox, fire native event so checked state will be right
			trigger: function() {
				if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
					this.click();
					return false;
				}
			},

			// For cross-browser consistency, don't fire native .click() on links
			_default: function( event ) {
				return jQuery.nodeName( event.target, "a" );
			}
		},

		beforeunload: {
			postDispatch: function( event ) {

				// Support: Firefox 20+
				// Firefox doesn't alert if the returnValue field is not set.
				if ( event.result !== undefined && event.originalEvent ) {
					event.originalEvent.returnValue = event.result;
				}
			}
		}
	}
};

jQuery.removeEvent = function( elem, type, handle ) {

	// This "if" is needed for plain objects
	if ( elem.removeEventListener ) {
		elem.removeEventListener( type, handle );
	}
};

jQuery.Event = function( src, props ) {

	// Allow instantiation without the 'new' keyword
	if ( !( this instanceof jQuery.Event ) ) {
		return new jQuery.Event( src, props );
	}

	// Event object
	if ( src && src.type ) {
		this.originalEvent = src;
		this.type = src.type;

		// Events bubbling up the document may have been marked as prevented
		// by a handler lower down the tree; reflect the correct value.
		this.isDefaultPrevented = src.defaultPrevented ||
				src.defaultPrevented === undefined &&

				// Support: Android<4.0
				src.returnValue === false ?
			returnTrue :
			returnFalse;

	// Event type
	} else {
		this.type = src;
	}

	// Put explicitly provided properties onto the event object
	if ( props ) {
		jQuery.extend( this, props );
	}

	// Create a timestamp if incoming event doesn't have one
	this.timeStamp = src && src.timeStamp || jQuery.now();

	// Mark it as fixed
	this[ jQuery.expando ] = true;
};

// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
	constructor: jQuery.Event,
	isDefaultPrevented: returnFalse,
	isPropagationStopped: returnFalse,
	isImmediatePropagationStopped: returnFalse,
	isSimulated: false,

	preventDefault: function() {
		var e = this.originalEvent;

		this.isDefaultPrevented = returnTrue;

		if ( e && !this.isSimulated ) {
			e.preventDefault();
		}
	},
	stopPropagation: function() {
		var e = this.originalEvent;

		this.isPropagationStopped = returnTrue;

		if ( e && !this.isSimulated ) {
			e.stopPropagation();
		}
	},
	stopImmediatePropagation: function() {
		var e = this.originalEvent;

		this.isImmediatePropagationStopped = returnTrue;

		if ( e && !this.isSimulated ) {
			e.stopImmediatePropagation();
		}

		this.stopPropagation();
	}
};

// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
//
// Support: Safari 7 only
// Safari sends mouseenter too often; see:
// https://code.google.com/p/chromium/issues/detail?id=470258
// for the description of the bug (it existed in older Chrome versions as well).
jQuery.each( {
	mouseenter: "mouseover",
	mouseleave: "mouseout",
	pointerenter: "pointerover",
	pointerleave: "pointerout"
}, function( orig, fix ) {
	jQuery.event.special[ orig ] = {
		delegateType: fix,
		bindType: fix,

		handle: function( event ) {
			var ret,
				target = this,
				related = event.relatedTarget,
				handleObj = event.handleObj;

			// For mouseenter/leave call the handler if related is outside the target.
			// NB: No relatedTarget if the mouse left/entered the browser window
			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
				event.type = handleObj.origType;
				ret = handleObj.handler.apply( this, arguments );
				event.type = fix;
			}
			return ret;
		}
	};
} );

jQuery.fn.extend( {
	on: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn );
	},
	one: function( types, selector, data, fn ) {
		return on( this, types, selector, data, fn, 1 );
	},
	off: function( types, selector, fn ) {
		var handleObj, type;
		if ( types && types.preventDefault && types.handleObj ) {

			// ( event )  dispatched jQuery.Event
			handleObj = types.handleObj;
			jQuery( types.delegateTarget ).off(
				handleObj.namespace ?
					handleObj.origType + "." + handleObj.namespace :
					handleObj.origType,
				handleObj.selector,
				handleObj.handler
			);
			return this;
		}
		if ( typeof types === "object" ) {

			// ( types-object [, selector] )
			for ( type in types ) {
				this.off( type, selector, types[ type ] );
			}
			return this;
		}
		if ( selector === false || typeof selector === "function" ) {

			// ( types [, fn] )
			fn = selector;
			selector = undefined;
		}
		if ( fn === false ) {
			fn = returnFalse;
		}
		return this.each( function() {
			jQuery.event.remove( this, types, fn, selector );
		} );
	}
} );


var
	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,

	// Support: IE 10-11, Edge 10240+
	// In IE/Edge using regex groups here causes severe slowdowns.
	// See https://connect.microsoft.com/IE/feedback/details/1736512/
	rnoInnerhtml = /<script|<style|<link/i,

	// checked="checked" or checked
	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
	rscriptTypeMasked = /^true\/(.*)/,
	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;

// Manipulating tables requires a tbody
function manipulationTarget( elem, content ) {
	return jQuery.nodeName( elem, "table" ) &&
		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?

		elem.getElementsByTagName( "tbody" )[ 0 ] ||
			elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) :
		elem;
}

// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
	elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
	return elem;
}
function restoreScript( elem ) {
	var match = rscriptTypeMasked.exec( elem.type );

	if ( match ) {
		elem.type = match[ 1 ];
	} else {
		elem.removeAttribute( "type" );
	}

	return elem;
}

function cloneCopyEvent( src, dest ) {
	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;

	if ( dest.nodeType !== 1 ) {
		return;
	}

	// 1. Copy private data: events, handlers, etc.
	if ( dataPriv.hasData( src ) ) {
		pdataOld = dataPriv.access( src );
		pdataCur = dataPriv.set( dest, pdataOld );
		events = pdataOld.events;

		if ( events ) {
			delete pdataCur.handle;
			pdataCur.events = {};

			for ( type in events ) {
				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
					jQuery.event.add( dest, type, events[ type ][ i ] );
				}
			}
		}
	}

	// 2. Copy user data
	if ( dataUser.hasData( src ) ) {
		udataOld = dataUser.access( src );
		udataCur = jQuery.extend( {}, udataOld );

		dataUser.set( dest, udataCur );
	}
}

// Fix IE bugs, see support tests
function fixInput( src, dest ) {
	var nodeName = dest.nodeName.toLowerCase();

	// Fails to persist the checked state of a cloned checkbox or radio button.
	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
		dest.checked = src.checked;

	// Fails to return the selected option to the default selected state when cloning options
	} else if ( nodeName === "input" || nodeName === "textarea" ) {
		dest.defaultValue = src.defaultValue;
	}
}

function domManip( collection, args, callback, ignored ) {

	// Flatten any nested arrays
	args = concat.apply( [], args );

	var fragment, first, scripts, hasScripts, node, doc,
		i = 0,
		l = collection.length,
		iNoClone = l - 1,
		value = args[ 0 ],
		isFunction = jQuery.isFunction( value );

	// We can't cloneNode fragments that contain checked, in WebKit
	if ( isFunction ||
			( l > 1 && typeof value === "string" &&
				!support.checkClone && rchecked.test( value ) ) ) {
		return collection.each( function( index ) {
			var self = collection.eq( index );
			if ( isFunction ) {
				args[ 0 ] = value.call( this, index, self.html() );
			}
			domManip( self, args, callback, ignored );
		} );
	}

	if ( l ) {
		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
		first = fragment.firstChild;

		if ( fragment.childNodes.length === 1 ) {
			fragment = first;
		}

		// Require either new content or an interest in ignored elements to invoke the callback
		if ( first || ignored ) {
			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
			hasScripts = scripts.length;

			// Use the original fragment for the last item
			// instead of the first because it can end up
			// being emptied incorrectly in certain situations (#8070).
			for ( ; i < l; i++ ) {
				node = fragment;

				if ( i !== iNoClone ) {
					node = jQuery.clone( node, true, true );

					// Keep references to cloned scripts for later restoration
					if ( hasScripts ) {

						// Support: Android<4.1, PhantomJS<2
						// push.apply(_, arraylike) throws on ancient WebKit
						jQuery.merge( scripts, getAll( node, "script" ) );
					}
				}

				callback.call( collection[ i ], node, i );
			}

			if ( hasScripts ) {
				doc = scripts[ scripts.length - 1 ].ownerDocument;

				// Reenable scripts
				jQuery.map( scripts, restoreScript );

				// Evaluate executable scripts on first document insertion
				for ( i = 0; i < hasScripts; i++ ) {
					node = scripts[ i ];
					if ( rscriptType.test( node.type || "" ) &&
						!dataPriv.access( node, "globalEval" ) &&
						jQuery.contains( doc, node ) ) {

						if ( node.src ) {

							// Optional AJAX dependency, but won't run scripts if not present
							if ( jQuery._evalUrl ) {
								jQuery._evalUrl( node.src );
							}
						} else {
							jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
						}
					}
				}
			}
		}
	}

	return collection;
}

function remove( elem, selector, keepData ) {
	var node,
		nodes = selector ? jQuery.filter( selector, elem ) : elem,
		i = 0;

	for ( ; ( node = nodes[ i ] ) != null; i++ ) {
		if ( !keepData && node.nodeType === 1 ) {
			jQuery.cleanData( getAll( node ) );
		}

		if ( node.parentNode ) {
			if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
				setGlobalEval( getAll( node, "script" ) );
			}
			node.parentNode.removeChild( node );
		}
	}

	return elem;
}

jQuery.extend( {
	htmlPrefilter: function( html ) {
		return html.replace( rxhtmlTag, "<$1></$2>" );
	},

	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
		var i, l, srcElements, destElements,
			clone = elem.cloneNode( true ),
			inPage = jQuery.contains( elem.ownerDocument, elem );

		// Fix IE cloning issues
		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
				!jQuery.isXMLDoc( elem ) ) {

			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
			destElements = getAll( clone );
			srcElements = getAll( elem );

			for ( i = 0, l = srcElements.length; i < l; i++ ) {
				fixInput( srcElements[ i ], destElements[ i ] );
			}
		}

		// Copy the events from the original to the clone
		if ( dataAndEvents ) {
			if ( deepDataAndEvents ) {
				srcElements = srcElements || getAll( elem );
				destElements = destElements || getAll( clone );

				for ( i = 0, l = srcElements.length; i < l; i++ ) {
					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
				}
			} else {
				cloneCopyEvent( elem, clone );
			}
		}

		// Preserve script evaluation history
		destElements = getAll( clone, "script" );
		if ( destElements.length > 0 ) {
			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
		}

		// Return the cloned set
		return clone;
	},

	cleanData: function( elems ) {
		var data, elem, type,
			special = jQuery.event.special,
			i = 0;

		for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
			if ( acceptData( elem ) ) {
				if ( ( data = elem[ dataPriv.expando ] ) ) {
					if ( data.events ) {
						for ( type in data.events ) {
							if ( special[ type ] ) {
								jQuery.event.remove( elem, type );

							// This is a shortcut to avoid jQuery.event.remove's overhead
							} else {
								jQuery.removeEvent( elem, type, data.handle );
							}
						}
					}

					// Support: Chrome <= 35-45+
					// Assign undefined instead of using delete, see Data#remove
					elem[ dataPriv.expando ] = undefined;
				}
				if ( elem[ dataUser.expando ] ) {

					// Support: Chrome <= 35-45+
					// Assign undefined instead of using delete, see Data#remove
					elem[ dataUser.expando ] = undefined;
				}
			}
		}
	}
} );

jQuery.fn.extend( {

	// Keep domManip exposed until 3.0 (gh-2225)
	domManip: domManip,

	detach: function( selector ) {
		return remove( this, selector, true );
	},

	remove: function( selector ) {
		return remove( this, selector );
	},

	text: function( value ) {
		return access( this, function( value ) {
			return value === undefined ?
				jQuery.text( this ) :
				this.empty().each( function() {
					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
						this.textContent = value;
					}
				} );
		}, null, value, arguments.length );
	},

	append: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.appendChild( elem );
			}
		} );
	},

	prepend: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
				var target = manipulationTarget( this, elem );
				target.insertBefore( elem, target.firstChild );
			}
		} );
	},

	before: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this );
			}
		} );
	},

	after: function() {
		return domManip( this, arguments, function( elem ) {
			if ( this.parentNode ) {
				this.parentNode.insertBefore( elem, this.nextSibling );
			}
		} );
	},

	empty: function() {
		var elem,
			i = 0;

		for ( ; ( elem = this[ i ] ) != null; i++ ) {
			if ( elem.nodeType === 1 ) {

				// Prevent memory leaks
				jQuery.cleanData( getAll( elem, false ) );

				// Remove any remaining nodes
				elem.textContent = "";
			}
		}

		return this;
	},

	clone: function( dataAndEvents, deepDataAndEvents ) {
		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;

		return this.map( function() {
			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
		} );
	},

	html: function( value ) {
		return access( this, function( value ) {
			var elem = this[ 0 ] || {},
				i = 0,
				l = this.length;

			if ( value === undefined && elem.nodeType === 1 ) {
				return elem.innerHTML;
			}

			// See if we can take a shortcut and just use innerHTML
			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {

				value = jQuery.htmlPrefilter( value );

				try {
					for ( ; i < l; i++ ) {
						elem = this[ i ] || {};

						// Remove element nodes and prevent memory leaks
						if ( elem.nodeType === 1 ) {
							jQuery.cleanData( getAll( elem, false ) );
							elem.innerHTML = value;
						}
					}

					elem = 0;

				// If using innerHTML throws an exception, use the fallback method
				} catch ( e ) {}
			}

			if ( elem ) {
				this.empty().append( value );
			}
		}, null, value, arguments.length );
	},

	replaceWith: function() {
		var ignored = [];

		// Make the changes, replacing each non-ignored context element with the new content
		return domManip( this, arguments, function( elem ) {
			var parent = this.parentNode;

			if ( jQuery.inArray( this, ignored ) < 0 ) {
				jQuery.cleanData( getAll( this ) );
				if ( parent ) {
					parent.replaceChild( elem, this );
				}
			}

		// Force callback invocation
		}, ignored );
	}
} );

jQuery.each( {
	appendTo: "append",
	prependTo: "prepend",
	insertBefore: "before",
	insertAfter: "after",
	replaceAll: "replaceWith"
}, function( name, original ) {
	jQuery.fn[ name ] = function( selector ) {
		var elems,
			ret = [],
			insert = jQuery( selector ),
			last = insert.length - 1,
			i = 0;

		for ( ; i <= last; i++ ) {
			elems = i === last ? this : this.clone( true );
			jQuery( insert[ i ] )[ original ]( elems );

			// Support: QtWebKit
			// .get() because push.apply(_, arraylike) throws
			push.apply( ret, elems.get() );
		}

		return this.pushStack( ret );
	};
} );


var iframe,
	elemdisplay = {

		// Support: Firefox
		// We have to pre-define these values for FF (#10227)
		HTML: "block",
		BODY: "block"
	};

/**
 * Retrieve the actual display of a element
 * @param {String} name nodeName of the element
 * @param {Object} doc Document object
 */

// Called only from within defaultDisplay
function actualDisplay( name, doc ) {
	var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),

		display = jQuery.css( elem[ 0 ], "display" );

	// We don't have any data stored on the element,
	// so use "detach" method as fast way to get rid of the element
	elem.detach();

	return display;
}

/**
 * Try to determine the default display value of an element
 * @param {String} nodeName
 */
function defaultDisplay( nodeName ) {
	var doc = document,
		display = elemdisplay[ nodeName ];

	if ( !display ) {
		display = actualDisplay( nodeName, doc );

		// If the simple way fails, read from inside an iframe
		if ( display === "none" || !display ) {

			// Use the already-created iframe if possible
			iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) )
				.appendTo( doc.documentElement );

			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
			doc = iframe[ 0 ].contentDocument;

			// Support: IE
			doc.write();
			doc.close();

			display = actualDisplay( nodeName, doc );
			iframe.detach();
		}

		// Store the correct default display
		elemdisplay[ nodeName ] = display;
	}

	return display;
}
var rmargin = ( /^margin/ );

var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );

var getStyles = function( elem ) {

		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
		// IE throws on elements created in popups
		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
		var view = elem.ownerDocument.defaultView;

		if ( !view || !view.opener ) {
			view = window;
		}

		return view.getComputedStyle( elem );
	};

var swap = function( elem, options, callback, args ) {
	var ret, name,
		old = {};

	// Remember the old values, and insert the new ones
	for ( name in options ) {
		old[ name ] = elem.style[ name ];
		elem.style[ name ] = options[ name ];
	}

	ret = callback.apply( elem, args || [] );

	// Revert the old values
	for ( name in options ) {
		elem.style[ name ] = old[ name ];
	}

	return ret;
};


var documentElement = document.documentElement;



( function() {
	var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
		container = document.createElement( "div" ),
		div = document.createElement( "div" );

	// Finish early in limited (non-browser) environments
	if ( !div.style ) {
		return;
	}

	// Support: IE9-11+
	// Style of cloned element affects source element cloned (#8908)
	div.style.backgroundClip = "content-box";
	div.cloneNode( true ).style.backgroundClip = "";
	support.clearCloneStyle = div.style.backgroundClip === "content-box";

	container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
		"padding:0;margin-top:1px;position:absolute";
	container.appendChild( div );

	// Executing both pixelPosition & boxSizingReliable tests require only one layout
	// so they're executed at the same time to save the second computation.
	function computeStyleTests() {
		div.style.cssText =

			// Support: Firefox<29, Android 2.3
			// Vendor-prefix box-sizing
			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" +
			"position:relative;display:block;" +
			"margin:auto;border:1px;padding:1px;" +
			"top:1%;width:50%";
		div.innerHTML = "";
		documentElement.appendChild( container );

		var divStyle = window.getComputedStyle( div );
		pixelPositionVal = divStyle.top !== "1%";
		reliableMarginLeftVal = divStyle.marginLeft === "2px";
		boxSizingReliableVal = divStyle.width === "4px";

		// Support: Android 4.0 - 4.3 only
		// Some styles come back with percentage values, even though they shouldn't
		div.style.marginRight = "50%";
		pixelMarginRightVal = divStyle.marginRight === "4px";

		documentElement.removeChild( container );
	}

	jQuery.extend( support, {
		pixelPosition: function() {

			// This test is executed only once but we still do memoizing
			// since we can use the boxSizingReliable pre-computing.
			// No need to check if the test was already performed, though.
			computeStyleTests();
			return pixelPositionVal;
		},
		boxSizingReliable: function() {
			if ( boxSizingReliableVal == null ) {
				computeStyleTests();
			}
			return boxSizingReliableVal;
		},
		pixelMarginRight: function() {

			// Support: Android 4.0-4.3
			// We're checking for boxSizingReliableVal here instead of pixelMarginRightVal
			// since that compresses better and they're computed together anyway.
			if ( boxSizingReliableVal == null ) {
				computeStyleTests();
			}
			return pixelMarginRightVal;
		},
		reliableMarginLeft: function() {

			// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37
			if ( boxSizingReliableVal == null ) {
				computeStyleTests();
			}
			return reliableMarginLeftVal;
		},
		reliableMarginRight: function() {

			// Support: Android 2.3
			// Check if div with explicit width and no margin-right incorrectly
			// gets computed margin-right based on width of container. (#3333)
			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
			// This support function is only executed once so no memoizing is needed.
			var ret,
				marginDiv = div.appendChild( document.createElement( "div" ) );

			// Reset CSS: box-sizing; display; margin; border; padding
			marginDiv.style.cssText = div.style.cssText =

				// Support: Android 2.3
				// Vendor-prefix box-sizing
				"-webkit-box-sizing:content-box;box-sizing:content-box;" +
				"display:block;margin:0;border:0;padding:0";
			marginDiv.style.marginRight = marginDiv.style.width = "0";
			div.style.width = "1px";
			documentElement.appendChild( container );

			ret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight );

			documentElement.removeChild( container );
			div.removeChild( marginDiv );

			return ret;
		}
	} );
} )();


function curCSS( elem, name, computed ) {
	var width, minWidth, maxWidth, ret,
		style = elem.style;

	computed = computed || getStyles( elem );
	ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;

	// Support: Opera 12.1x only
	// Fall back to style even without computed
	// computed is undefined for elems on document fragments
	if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {
		ret = jQuery.style( elem, name );
	}

	// Support: IE9
	// getPropertyValue is only needed for .css('filter') (#12537)
	if ( computed ) {

		// A tribute to the "awesome hack by Dean Edwards"
		// Android Browser returns percentage for some values,
		// but width seems to be reliably pixels.
		// This is against the CSSOM draft spec:
		// http://dev.w3.org/csswg/cssom/#resolved-values
		if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {

			// Remember the original values
			width = style.width;
			minWidth = style.minWidth;
			maxWidth = style.maxWidth;

			// Put in the new values to get a computed value out
			style.minWidth = style.maxWidth = style.width = ret;
			ret = computed.width;

			// Revert the changed values
			style.width = width;
			style.minWidth = minWidth;
			style.maxWidth = maxWidth;
		}
	}

	return ret !== undefined ?

		// Support: IE9-11+
		// IE returns zIndex value as an integer.
		ret + "" :
		ret;
}


function addGetHookIf( conditionFn, hookFn ) {

	// Define the hook, we'll check on the first run if it's really needed.
	return {
		get: function() {
			if ( conditionFn() ) {

				// Hook not needed (or it's not possible to use it due
				// to missing dependency), remove it.
				delete this.get;
				return;
			}

			// Hook needed; redefine it so that the support test is not executed again.
			return ( this.get = hookFn ).apply( this, arguments );
		}
	};
}


var

	// Swappable if display is none or starts with table
	// except "table", "table-cell", or "table-caption"
	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
	rdisplayswap = /^(none|table(?!-c[ea]).+)/,

	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
	cssNormalTransform = {
		letterSpacing: "0",
		fontWeight: "400"
	},

	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
	emptyStyle = document.createElement( "div" ).style;

// Return a css property mapped to a potentially vendor prefixed property
function vendorPropName( name ) {

	// Shortcut for names that are not vendor prefixed
	if ( name in emptyStyle ) {
		return name;
	}

	// Check for vendor prefixed names
	var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
		i = cssPrefixes.length;

	while ( i-- ) {
		name = cssPrefixes[ i ] + capName;
		if ( name in emptyStyle ) {
			return name;
		}
	}
}

function setPositiveNumber( elem, value, subtract ) {

	// Any relative (+/-) values have already been
	// normalized at this point
	var matches = rcssNum.exec( value );
	return matches ?

		// Guard against undefined "subtract", e.g., when used as in cssHooks
		Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
		value;
}

function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
	var i = extra === ( isBorderBox ? "border" : "content" ) ?

		// If we already have the right measurement, avoid augmentation
		4 :

		// Otherwise initialize for horizontal or vertical properties
		name === "width" ? 1 : 0,

		val = 0;

	for ( ; i < 4; i += 2 ) {

		// Both box models exclude margin, so add it if we want it
		if ( extra === "margin" ) {
			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
		}

		if ( isBorderBox ) {

			// border-box includes padding, so remove it if we want content
			if ( extra === "content" ) {
				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
			}

			// At this point, extra isn't border nor margin, so remove border
			if ( extra !== "margin" ) {
				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}
		} else {

			// At this point, extra isn't content, so add padding
			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );

			// At this point, extra isn't content nor padding, so add border
			if ( extra !== "padding" ) {
				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
			}
		}
	}

	return val;
}

function getWidthOrHeight( elem, name, extra ) {

	// Start with offset property, which is equivalent to the border-box value
	var valueIsBorderBox = true,
		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
		styles = getStyles( elem ),
		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";

	// Some non-html elements return undefined for offsetWidth, so check for null/undefined
	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
	if ( val <= 0 || val == null ) {

		// Fall back to computed then uncomputed css if necessary
		val = curCSS( elem, name, styles );
		if ( val < 0 || val == null ) {
			val = elem.style[ name ];
		}

		// Computed unit is not pixels. Stop here and return.
		if ( rnumnonpx.test( val ) ) {
			return val;
		}

		// Check for style in case a browser which returns unreliable values
		// for getComputedStyle silently falls back to the reliable elem.style
		valueIsBorderBox = isBorderBox &&
			( support.boxSizingReliable() || val === elem.style[ name ] );

		// Normalize "", auto, and prepare for extra
		val = parseFloat( val ) || 0;
	}

	// Use the active box-sizing model to add/subtract irrelevant styles
	return ( val +
		augmentWidthOrHeight(
			elem,
			name,
			extra || ( isBorderBox ? "border" : "content" ),
			valueIsBorderBox,
			styles
		)
	) + "px";
}

function showHide( elements, show ) {
	var display, elem, hidden,
		values = [],
		index = 0,
		length = elements.length;

	for ( ; index < length; index++ ) {
		elem = elements[ index ];
		if ( !elem.style ) {
			continue;
		}

		values[ index ] = dataPriv.get( elem, "olddisplay" );
		display = elem.style.display;
		if ( show ) {

			// Reset the inline display of this element to learn if it is
			// being hidden by cascaded rules or not
			if ( !values[ index ] && display === "none" ) {
				elem.style.display = "";
			}

			// Set elements which have been overridden with display: none
			// in a stylesheet to whatever the default browser style is
			// for such an element
			if ( elem.style.display === "" && isHidden( elem ) ) {
				values[ index ] = dataPriv.access(
					elem,
					"olddisplay",
					defaultDisplay( elem.nodeName )
				);
			}
		} else {
			hidden = isHidden( elem );

			if ( display !== "none" || !hidden ) {
				dataPriv.set(
					elem,
					"olddisplay",
					hidden ? display : jQuery.css( elem, "display" )
				);
			}
		}
	}

	// Set the display of most of the elements in a second loop
	// to avoid the constant reflow
	for ( index = 0; index < length; index++ ) {
		elem = elements[ index ];
		if ( !elem.style ) {
			continue;
		}
		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
			elem.style.display = show ? values[ index ] || "" : "none";
		}
	}

	return elements;
}

jQuery.extend( {

	// Add in style property hooks for overriding the default
	// behavior of getting and setting a style property
	cssHooks: {
		opacity: {
			get: function( elem, computed ) {
				if ( computed ) {

					// We should always get a number back from opacity
					var ret = curCSS( elem, "opacity" );
					return ret === "" ? "1" : ret;
				}
			}
		}
	},

	// Don't automatically add "px" to these possibly-unitless properties
	cssNumber: {
		"animationIterationCount": true,
		"columnCount": true,
		"fillOpacity": true,
		"flexGrow": true,
		"flexShrink": true,
		"fontWeight": true,
		"lineHeight": true,
		"opacity": true,
		"order": true,
		"orphans": true,
		"widows": true,
		"zIndex": true,
		"zoom": true
	},

	// Add in properties whose names you wish to fix before
	// setting or getting the value
	cssProps: {
		"float": "cssFloat"
	},

	// Get and set the style property on a DOM Node
	style: function( elem, name, value, extra ) {

		// Don't set styles on text and comment nodes
		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
			return;
		}

		// Make sure that we're working with the right name
		var ret, type, hooks,
			origName = jQuery.camelCase( name ),
			style = elem.style;

		name = jQuery.cssProps[ origName ] ||
			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );

		// Gets hook for the prefixed version, then unprefixed version
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// Check if we're setting a value
		if ( value !== undefined ) {
			type = typeof value;

			// Convert "+=" or "-=" to relative numbers (#7345)
			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
				value = adjustCSS( elem, name, ret );

				// Fixes bug #9237
				type = "number";
			}

			// Make sure that null and NaN values aren't set (#7116)
			if ( value == null || value !== value ) {
				return;
			}

			// If a number was passed in, add the unit (except for certain CSS properties)
			if ( type === "number" ) {
				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
			}

			// Support: IE9-11+
			// background-* props affect original clone's values
			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
				style[ name ] = "inherit";
			}

			// If a hook was provided, use that value, otherwise just set the specified value
			if ( !hooks || !( "set" in hooks ) ||
				( value = hooks.set( elem, value, extra ) ) !== undefined ) {

				style[ name ] = value;
			}

		} else {

			// If a hook was provided get the non-computed value from there
			if ( hooks && "get" in hooks &&
				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {

				return ret;
			}

			// Otherwise just get the value from the style object
			return style[ name ];
		}
	},

	css: function( elem, name, extra, styles ) {
		var val, num, hooks,
			origName = jQuery.camelCase( name );

		// Make sure that we're working with the right name
		name = jQuery.cssProps[ origName ] ||
			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );

		// Try prefixed name followed by the unprefixed name
		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

		// If a hook was provided get the computed value from there
		if ( hooks && "get" in hooks ) {
			val = hooks.get( elem, true, extra );
		}

		// Otherwise, if a way to get the computed value exists, use that
		if ( val === undefined ) {
			val = curCSS( elem, name, styles );
		}

		// Convert "normal" to computed value
		if ( val === "normal" && name in cssNormalTransform ) {
			val = cssNormalTransform[ name ];
		}

		// Make numeric if forced or a qualifier was provided and val looks numeric
		if ( extra === "" || extra ) {
			num = parseFloat( val );
			return extra === true || isFinite( num ) ? num || 0 : val;
		}
		return val;
	}
} );

jQuery.each( [ "height", "width" ], function( i, name ) {
	jQuery.cssHooks[ name ] = {
		get: function( elem, computed, extra ) {
			if ( computed ) {

				// Certain elements can have dimension info if we invisibly show them
				// but it must have a current display style that would benefit
				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
					elem.offsetWidth === 0 ?
						swap( elem, cssShow, function() {
							return getWidthOrHeight( elem, name, extra );
						} ) :
						getWidthOrHeight( elem, name, extra );
			}
		},

		set: function( elem, value, extra ) {
			var matches,
				styles = extra && getStyles( elem ),
				subtract = extra && augmentWidthOrHeight(
					elem,
					name,
					extra,
					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
					styles
				);

			// Convert to pixels if value adjustment is needed
			if ( subtract && ( matches = rcssNum.exec( value ) ) &&
				( matches[ 3 ] || "px" ) !== "px" ) {

				elem.style[ name ] = value;
				value = jQuery.css( elem, name );
			}

			return setPositiveNumber( elem, value, subtract );
		}
	};
} );

jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
	function( elem, computed ) {
		if ( computed ) {
			return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
				elem.getBoundingClientRect().left -
					swap( elem, { marginLeft: 0 }, function() {
						return elem.getBoundingClientRect().left;
					} )
				) + "px";
		}
	}
);

// Support: Android 2.3
jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
	function( elem, computed ) {
		if ( computed ) {
			return swap( elem, { "display": "inline-block" },
				curCSS, [ elem, "marginRight" ] );
		}
	}
);

// These hooks are used by animate to expand properties
jQuery.each( {
	margin: "",
	padding: "",
	border: "Width"
}, function( prefix, suffix ) {
	jQuery.cssHooks[ prefix + suffix ] = {
		expand: function( value ) {
			var i = 0,
				expanded = {},

				// Assumes a single number if not a string
				parts = typeof value === "string" ? value.split( " " ) : [ value ];

			for ( ; i < 4; i++ ) {
				expanded[ prefix + cssExpand[ i ] + suffix ] =
					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
			}

			return expanded;
		}
	};

	if ( !rmargin.test( prefix ) ) {
		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
	}
} );

jQuery.fn.extend( {
	css: function( name, value ) {
		return access( this, function( elem, name, value ) {
			var styles, len,
				map = {},
				i = 0;

			if ( jQuery.isArray( name ) ) {
				styles = getStyles( elem );
				len = name.length;

				for ( ; i < len; i++ ) {
					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
				}

				return map;
			}

			return value !== undefined ?
				jQuery.style( elem, name, value ) :
				jQuery.css( elem, name );
		}, name, value, arguments.length > 1 );
	},
	show: function() {
		return showHide( this, true );
	},
	hide: function() {
		return showHide( this );
	},
	toggle: function( state ) {
		if ( typeof state === "boolean" ) {
			return state ? this.show() : this.hide();
		}

		return this.each( function() {
			if ( isHidden( this ) ) {
				jQuery( this ).show();
			} else {
				jQuery( this ).hide();
			}
		} );
	}
} );


function Tween( elem, options, prop, end, easing ) {
	return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;

Tween.prototype = {
	constructor: Tween,
	init: function( elem, options, prop, end, easing, unit ) {
		this.elem = elem;
		this.prop = prop;
		this.easing = easing || jQuery.easing._default;
		this.options = options;
		this.start = this.now = this.cur();
		this.end = end;
		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
	},
	cur: function() {
		var hooks = Tween.propHooks[ this.prop ];

		return hooks && hooks.get ?
			hooks.get( this ) :
			Tween.propHooks._default.get( this );
	},
	run: function( percent ) {
		var eased,
			hooks = Tween.propHooks[ this.prop ];

		if ( this.options.duration ) {
			this.pos = eased = jQuery.easing[ this.easing ](
				percent, this.options.duration * percent, 0, 1, this.options.duration
			);
		} else {
			this.pos = eased = percent;
		}
		this.now = ( this.end - this.start ) * eased + this.start;

		if ( this.options.step ) {
			this.options.step.call( this.elem, this.now, this );
		}

		if ( hooks && hooks.set ) {
			hooks.set( this );
		} else {
			Tween.propHooks._default.set( this );
		}
		return this;
	}
};

Tween.prototype.init.prototype = Tween.prototype;

Tween.propHooks = {
	_default: {
		get: function( tween ) {
			var result;

			// Use a property on the element directly when it is not a DOM element,
			// or when there is no matching style property that exists.
			if ( tween.elem.nodeType !== 1 ||
				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
				return tween.elem[ tween.prop ];
			}

			// Passing an empty string as a 3rd parameter to .css will automatically
			// attempt a parseFloat and fallback to a string if the parse fails.
			// Simple values such as "10px" are parsed to Float;
			// complex values such as "rotate(1rad)" are returned as-is.
			result = jQuery.css( tween.elem, tween.prop, "" );

			// Empty strings, null, undefined and "auto" are converted to 0.
			return !result || result === "auto" ? 0 : result;
		},
		set: function( tween ) {

			// Use step hook for back compat.
			// Use cssHook if its there.
			// Use .style if available and use plain properties where available.
			if ( jQuery.fx.step[ tween.prop ] ) {
				jQuery.fx.step[ tween.prop ]( tween );
			} else if ( tween.elem.nodeType === 1 &&
				( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
					jQuery.cssHooks[ tween.prop ] ) ) {
				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
			} else {
				tween.elem[ tween.prop ] = tween.now;
			}
		}
	}
};

// Support: IE9
// Panic based approach to setting things on disconnected nodes
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
	set: function( tween ) {
		if ( tween.elem.nodeType && tween.elem.parentNode ) {
			tween.elem[ tween.prop ] = tween.now;
		}
	}
};

jQuery.easing = {
	linear: function( p ) {
		return p;
	},
	swing: function( p ) {
		return 0.5 - Math.cos( p * Math.PI ) / 2;
	},
	_default: "swing"
};

jQuery.fx = Tween.prototype.init;

// Back Compat <1.8 extension point
jQuery.fx.step = {};




var
	fxNow, timerId,
	rfxtypes = /^(?:toggle|show|hide)$/,
	rrun = /queueHooks$/;

// Animations created synchronously will run synchronously
function createFxNow() {
	window.setTimeout( function() {
		fxNow = undefined;
	} );
	return ( fxNow = jQuery.now() );
}

// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
	var which,
		i = 0,
		attrs = { height: type };

	// If we include width, step value is 1 to do all cssExpand values,
	// otherwise step value is 2 to skip over Left and Right
	includeWidth = includeWidth ? 1 : 0;
	for ( ; i < 4 ; i += 2 - includeWidth ) {
		which = cssExpand[ i ];
		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
	}

	if ( includeWidth ) {
		attrs.opacity = attrs.width = type;
	}

	return attrs;
}

function createTween( value, prop, animation ) {
	var tween,
		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
		index = 0,
		length = collection.length;
	for ( ; index < length; index++ ) {
		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {

			// We're done with this property
			return tween;
		}
	}
}

function defaultPrefilter( elem, props, opts ) {
	/* jshint validthis: true */
	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
		anim = this,
		orig = {},
		style = elem.style,
		hidden = elem.nodeType && isHidden( elem ),
		dataShow = dataPriv.get( elem, "fxshow" );

	// Handle queue: false promises
	if ( !opts.queue ) {
		hooks = jQuery._queueHooks( elem, "fx" );
		if ( hooks.unqueued == null ) {
			hooks.unqueued = 0;
			oldfire = hooks.empty.fire;
			hooks.empty.fire = function() {
				if ( !hooks.unqueued ) {
					oldfire();
				}
			};
		}
		hooks.unqueued++;

		anim.always( function() {

			// Ensure the complete handler is called before this completes
			anim.always( function() {
				hooks.unqueued--;
				if ( !jQuery.queue( elem, "fx" ).length ) {
					hooks.empty.fire();
				}
			} );
		} );
	}

	// Height/width overflow pass
	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {

		// Make sure that nothing sneaks out
		// Record all 3 overflow attributes because IE9-10 do not
		// change the overflow attribute when overflowX and
		// overflowY are set to the same value
		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];

		// Set display property to inline-block for height/width
		// animations on inline elements that are having width/height animated
		display = jQuery.css( elem, "display" );

		// Test default display if display is currently "none"
		checkDisplay = display === "none" ?
			dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;

		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
			style.display = "inline-block";
		}
	}

	if ( opts.overflow ) {
		style.overflow = "hidden";
		anim.always( function() {
			style.overflow = opts.overflow[ 0 ];
			style.overflowX = opts.overflow[ 1 ];
			style.overflowY = opts.overflow[ 2 ];
		} );
	}

	// show/hide pass
	for ( prop in props ) {
		value = props[ prop ];
		if ( rfxtypes.exec( value ) ) {
			delete props[ prop ];
			toggle = toggle || value === "toggle";
			if ( value === ( hidden ? "hide" : "show" ) ) {

				// If there is dataShow left over from a stopped hide or show
				// and we are going to proceed with show, we should pretend to be hidden
				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
					hidden = true;
				} else {
					continue;
				}
			}
			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );

		// Any non-fx value stops us from restoring the original display value
		} else {
			display = undefined;
		}
	}

	if ( !jQuery.isEmptyObject( orig ) ) {
		if ( dataShow ) {
			if ( "hidden" in dataShow ) {
				hidden = dataShow.hidden;
			}
		} else {
			dataShow = dataPriv.access( elem, "fxshow", {} );
		}

		// Store state if its toggle - enables .stop().toggle() to "reverse"
		if ( toggle ) {
			dataShow.hidden = !hidden;
		}
		if ( hidden ) {
			jQuery( elem ).show();
		} else {
			anim.done( function() {
				jQuery( elem ).hide();
			} );
		}
		anim.done( function() {
			var prop;

			dataPriv.remove( elem, "fxshow" );
			for ( prop in orig ) {
				jQuery.style( elem, prop, orig[ prop ] );
			}
		} );
		for ( prop in orig ) {
			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );

			if ( !( prop in dataShow ) ) {
				dataShow[ prop ] = tween.start;
				if ( hidden ) {
					tween.end = tween.start;
					tween.start = prop === "width" || prop === "height" ? 1 : 0;
				}
			}
		}

	// If this is a noop like .hide().hide(), restore an overwritten display value
	} else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
		style.display = display;
	}
}

function propFilter( props, specialEasing ) {
	var index, name, easing, value, hooks;

	// camelCase, specialEasing and expand cssHook pass
	for ( index in props ) {
		name = jQuery.camelCase( index );
		easing = specialEasing[ name ];
		value = props[ index ];
		if ( jQuery.isArray( value ) ) {
			easing = value[ 1 ];
			value = props[ index ] = value[ 0 ];
		}

		if ( index !== name ) {
			props[ name ] = value;
			delete props[ index ];
		}

		hooks = jQuery.cssHooks[ name ];
		if ( hooks && "expand" in hooks ) {
			value = hooks.expand( value );
			delete props[ name ];

			// Not quite $.extend, this won't overwrite existing keys.
			// Reusing 'index' because we have the correct "name"
			for ( index in value ) {
				if ( !( index in props ) ) {
					props[ index ] = value[ index ];
					specialEasing[ index ] = easing;
				}
			}
		} else {
			specialEasing[ name ] = easing;
		}
	}
}

function Animation( elem, properties, options ) {
	var result,
		stopped,
		index = 0,
		length = Animation.prefilters.length,
		deferred = jQuery.Deferred().always( function() {

			// Don't match elem in the :animated selector
			delete tick.elem;
		} ),
		tick = function() {
			if ( stopped ) {
				return false;
			}
			var currentTime = fxNow || createFxNow(),
				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),

				// Support: Android 2.3
				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
				temp = remaining / animation.duration || 0,
				percent = 1 - temp,
				index = 0,
				length = animation.tweens.length;

			for ( ; index < length ; index++ ) {
				animation.tweens[ index ].run( percent );
			}

			deferred.notifyWith( elem, [ animation, percent, remaining ] );

			if ( percent < 1 && length ) {
				return remaining;
			} else {
				deferred.resolveWith( elem, [ animation ] );
				return false;
			}
		},
		animation = deferred.promise( {
			elem: elem,
			props: jQuery.extend( {}, properties ),
			opts: jQuery.extend( true, {
				specialEasing: {},
				easing: jQuery.easing._default
			}, options ),
			originalProperties: properties,
			originalOptions: options,
			startTime: fxNow || createFxNow(),
			duration: options.duration,
			tweens: [],
			createTween: function( prop, end ) {
				var tween = jQuery.Tween( elem, animation.opts, prop, end,
						animation.opts.specialEasing[ prop ] || animation.opts.easing );
				animation.tweens.push( tween );
				return tween;
			},
			stop: function( gotoEnd ) {
				var index = 0,

					// If we are going to the end, we want to run all the tweens
					// otherwise we skip this part
					length = gotoEnd ? animation.tweens.length : 0;
				if ( stopped ) {
					return this;
				}
				stopped = true;
				for ( ; index < length ; index++ ) {
					animation.tweens[ index ].run( 1 );
				}

				// Resolve when we played the last frame; otherwise, reject
				if ( gotoEnd ) {
					deferred.notifyWith( elem, [ animation, 1, 0 ] );
					deferred.resolveWith( elem, [ animation, gotoEnd ] );
				} else {
					deferred.rejectWith( elem, [ animation, gotoEnd ] );
				}
				return this;
			}
		} ),
		props = animation.props;

	propFilter( props, animation.opts.specialEasing );

	for ( ; index < length ; index++ ) {
		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
		if ( result ) {
			if ( jQuery.isFunction( result.stop ) ) {
				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
					jQuery.proxy( result.stop, result );
			}
			return result;
		}
	}

	jQuery.map( props, createTween, animation );

	if ( jQuery.isFunction( animation.opts.start ) ) {
		animation.opts.start.call( elem, animation );
	}

	jQuery.fx.timer(
		jQuery.extend( tick, {
			elem: elem,
			anim: animation,
			queue: animation.opts.queue
		} )
	);

	// attach callbacks from options
	return animation.progress( animation.opts.progress )
		.done( animation.opts.done, animation.opts.complete )
		.fail( animation.opts.fail )
		.always( animation.opts.always );
}

jQuery.Animation = jQuery.extend( Animation, {
	tweeners: {
		"*": [ function( prop, value ) {
			var tween = this.createTween( prop, value );
			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
			return tween;
		} ]
	},

	tweener: function( props, callback ) {
		if ( jQuery.isFunction( props ) ) {
			callback = props;
			props = [ "*" ];
		} else {
			props = props.match( rnotwhite );
		}

		var prop,
			index = 0,
			length = props.length;

		for ( ; index < length ; index++ ) {
			prop = props[ index ];
			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
			Animation.tweeners[ prop ].unshift( callback );
		}
	},

	prefilters: [ defaultPrefilter ],

	prefilter: function( callback, prepend ) {
		if ( prepend ) {
			Animation.prefilters.unshift( callback );
		} else {
			Animation.prefilters.push( callback );
		}
	}
} );

jQuery.speed = function( speed, easing, fn ) {
	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
		complete: fn || !fn && easing ||
			jQuery.isFunction( speed ) && speed,
		duration: speed,
		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
	};

	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ?
		opt.duration : opt.duration in jQuery.fx.speeds ?
			jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;

	// Normalize opt.queue - true/undefined/null -> "fx"
	if ( opt.queue == null || opt.queue === true ) {
		opt.queue = "fx";
	}

	// Queueing
	opt.old = opt.complete;

	opt.complete = function() {
		if ( jQuery.isFunction( opt.old ) ) {
			opt.old.call( this );
		}

		if ( opt.queue ) {
			jQuery.dequeue( this, opt.queue );
		}
	};

	return opt;
};

jQuery.fn.extend( {
	fadeTo: function( speed, to, easing, callback ) {

		// Show any hidden elements after setting opacity to 0
		return this.filter( isHidden ).css( "opacity", 0 ).show()

			// Animate to the value specified
			.end().animate( { opacity: to }, speed, easing, callback );
	},
	animate: function( prop, speed, easing, callback ) {
		var empty = jQuery.isEmptyObject( prop ),
			optall = jQuery.speed( speed, easing, callback ),
			doAnimation = function() {

				// Operate on a copy of prop so per-property easing won't be lost
				var anim = Animation( this, jQuery.extend( {}, prop ), optall );

				// Empty animations, or finishing resolves immediately
				if ( empty || dataPriv.get( this, "finish" ) ) {
					anim.stop( true );
				}
			};
			doAnimation.finish = doAnimation;

		return empty || optall.queue === false ?
			this.each( doAnimation ) :
			this.queue( optall.queue, doAnimation );
	},
	stop: function( type, clearQueue, gotoEnd ) {
		var stopQueue = function( hooks ) {
			var stop = hooks.stop;
			delete hooks.stop;
			stop( gotoEnd );
		};

		if ( typeof type !== "string" ) {
			gotoEnd = clearQueue;
			clearQueue = type;
			type = undefined;
		}
		if ( clearQueue && type !== false ) {
			this.queue( type || "fx", [] );
		}

		return this.each( function() {
			var dequeue = true,
				index = type != null && type + "queueHooks",
				timers = jQuery.timers,
				data = dataPriv.get( this );

			if ( index ) {
				if ( data[ index ] && data[ index ].stop ) {
					stopQueue( data[ index ] );
				}
			} else {
				for ( index in data ) {
					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
						stopQueue( data[ index ] );
					}
				}
			}

			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this &&
					( type == null || timers[ index ].queue === type ) ) {

					timers[ index ].anim.stop( gotoEnd );
					dequeue = false;
					timers.splice( index, 1 );
				}
			}

			// Start the next in the queue if the last step wasn't forced.
			// Timers currently will call their complete callbacks, which
			// will dequeue but only if they were gotoEnd.
			if ( dequeue || !gotoEnd ) {
				jQuery.dequeue( this, type );
			}
		} );
	},
	finish: function( type ) {
		if ( type !== false ) {
			type = type || "fx";
		}
		return this.each( function() {
			var index,
				data = dataPriv.get( this ),
				queue = data[ type + "queue" ],
				hooks = data[ type + "queueHooks" ],
				timers = jQuery.timers,
				length = queue ? queue.length : 0;

			// Enable finishing flag on private data
			data.finish = true;

			// Empty the queue first
			jQuery.queue( this, type, [] );

			if ( hooks && hooks.stop ) {
				hooks.stop.call( this, true );
			}

			// Look for any active animations, and finish them
			for ( index = timers.length; index--; ) {
				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
					timers[ index ].anim.stop( true );
					timers.splice( index, 1 );
				}
			}

			// Look for any animations in the old queue and finish them
			for ( index = 0; index < length; index++ ) {
				if ( queue[ index ] && queue[ index ].finish ) {
					queue[ index ].finish.call( this );
				}
			}

			// Turn off finishing flag
			delete data.finish;
		} );
	}
} );

jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
	var cssFn = jQuery.fn[ name ];
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return speed == null || typeof speed === "boolean" ?
			cssFn.apply( this, arguments ) :
			this.animate( genFx( name, true ), speed, easing, callback );
	};
} );

// Generate shortcuts for custom animations
jQuery.each( {
	slideDown: genFx( "show" ),
	slideUp: genFx( "hide" ),
	slideToggle: genFx( "toggle" ),
	fadeIn: { opacity: "show" },
	fadeOut: { opacity: "hide" },
	fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
	jQuery.fn[ name ] = function( speed, easing, callback ) {
		return this.animate( props, speed, easing, callback );
	};
} );

jQuery.timers = [];
jQuery.fx.tick = function() {
	var timer,
		i = 0,
		timers = jQuery.timers;

	fxNow = jQuery.now();

	for ( ; i < timers.length; i++ ) {
		timer = timers[ i ];

		// Checks the timer has not already been removed
		if ( !timer() && timers[ i ] === timer ) {
			timers.splice( i--, 1 );
		}
	}

	if ( !timers.length ) {
		jQuery.fx.stop();
	}
	fxNow = undefined;
};

jQuery.fx.timer = function( timer ) {
	jQuery.timers.push( timer );
	if ( timer() ) {
		jQuery.fx.start();
	} else {
		jQuery.timers.pop();
	}
};

jQuery.fx.interval = 13;
jQuery.fx.start = function() {
	if ( !timerId ) {
		timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
	}
};

jQuery.fx.stop = function() {
	window.clearInterval( timerId );

	timerId = null;
};

jQuery.fx.speeds = {
	slow: 600,
	fast: 200,

	// Default speed
	_default: 400
};


// Based off of the plugin by Clint Helfers, with permission.
// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
jQuery.fn.delay = function( time, type ) {
	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
	type = type || "fx";

	return this.queue( type, function( next, hooks ) {
		var timeout = window.setTimeout( next, time );
		hooks.stop = function() {
			window.clearTimeout( timeout );
		};
	} );
};


( function() {
	var input = document.createElement( "input" ),
		select = document.createElement( "select" ),
		opt = select.appendChild( document.createElement( "option" ) );

	input.type = "checkbox";

	// Support: iOS<=5.1, Android<=4.2+
	// Default value for a checkbox should be "on"
	support.checkOn = input.value !== "";

	// Support: IE<=11+
	// Must access selectedIndex to make default options select
	support.optSelected = opt.selected;

	// Support: Android<=2.3
	// Options inside disabled selects are incorrectly marked as disabled
	select.disabled = true;
	support.optDisabled = !opt.disabled;

	// Support: IE<=11+
	// An input loses its value after becoming a radio
	input = document.createElement( "input" );
	input.value = "t";
	input.type = "radio";
	support.radioValue = input.value === "t";
} )();


var boolHook,
	attrHandle = jQuery.expr.attrHandle;

jQuery.fn.extend( {
	attr: function( name, value ) {
		return access( this, jQuery.attr, name, value, arguments.length > 1 );
	},

	removeAttr: function( name ) {
		return this.each( function() {
			jQuery.removeAttr( this, name );
		} );
	}
} );

jQuery.extend( {
	attr: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set attributes on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		// Fallback to prop when attributes are not supported
		if ( typeof elem.getAttribute === "undefined" ) {
			return jQuery.prop( elem, name, value );
		}

		// All attributes are lowercase
		// Grab necessary hook if one is defined
		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
			name = name.toLowerCase();
			hooks = jQuery.attrHooks[ name ] ||
				( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
		}

		if ( value !== undefined ) {
			if ( value === null ) {
				jQuery.removeAttr( elem, name );
				return;
			}

			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			elem.setAttribute( name, value + "" );
			return value;
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		ret = jQuery.find.attr( elem, name );

		// Non-existent attributes return null, we normalize to undefined
		return ret == null ? undefined : ret;
	},

	attrHooks: {
		type: {
			set: function( elem, value ) {
				if ( !support.radioValue && value === "radio" &&
					jQuery.nodeName( elem, "input" ) ) {
					var val = elem.value;
					elem.setAttribute( "type", value );
					if ( val ) {
						elem.value = val;
					}
					return value;
				}
			}
		}
	},

	removeAttr: function( elem, value ) {
		var name, propName,
			i = 0,
			attrNames = value && value.match( rnotwhite );

		if ( attrNames && elem.nodeType === 1 ) {
			while ( ( name = attrNames[ i++ ] ) ) {
				propName = jQuery.propFix[ name ] || name;

				// Boolean attributes get special treatment (#10870)
				if ( jQuery.expr.match.bool.test( name ) ) {

					// Set corresponding property to false
					elem[ propName ] = false;
				}

				elem.removeAttribute( name );
			}
		}
	}
} );

// Hooks for boolean attributes
boolHook = {
	set: function( elem, value, name ) {
		if ( value === false ) {

			// Remove boolean attributes when set to false
			jQuery.removeAttr( elem, name );
		} else {
			elem.setAttribute( name, name );
		}
		return name;
	}
};
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
	var getter = attrHandle[ name ] || jQuery.find.attr;

	attrHandle[ name ] = function( elem, name, isXML ) {
		var ret, handle;
		if ( !isXML ) {

			// Avoid an infinite loop by temporarily removing this function from the getter
			handle = attrHandle[ name ];
			attrHandle[ name ] = ret;
			ret = getter( elem, name, isXML ) != null ?
				name.toLowerCase() :
				null;
			attrHandle[ name ] = handle;
		}
		return ret;
	};
} );




var rfocusable = /^(?:input|select|textarea|button)$/i,
	rclickable = /^(?:a|area)$/i;

jQuery.fn.extend( {
	prop: function( name, value ) {
		return access( this, jQuery.prop, name, value, arguments.length > 1 );
	},

	removeProp: function( name ) {
		return this.each( function() {
			delete this[ jQuery.propFix[ name ] || name ];
		} );
	}
} );

jQuery.extend( {
	prop: function( elem, name, value ) {
		var ret, hooks,
			nType = elem.nodeType;

		// Don't get/set properties on text, comment and attribute nodes
		if ( nType === 3 || nType === 8 || nType === 2 ) {
			return;
		}

		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {

			// Fix name and attach hooks
			name = jQuery.propFix[ name ] || name;
			hooks = jQuery.propHooks[ name ];
		}

		if ( value !== undefined ) {
			if ( hooks && "set" in hooks &&
				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
				return ret;
			}

			return ( elem[ name ] = value );
		}

		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
			return ret;
		}

		return elem[ name ];
	},

	propHooks: {
		tabIndex: {
			get: function( elem ) {

				// elem.tabIndex doesn't always return the
				// correct value when it hasn't been explicitly set
				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
				// Use proper attribute retrieval(#12072)
				var tabindex = jQuery.find.attr( elem, "tabindex" );

				return tabindex ?
					parseInt( tabindex, 10 ) :
					rfocusable.test( elem.nodeName ) ||
						rclickable.test( elem.nodeName ) && elem.href ?
							0 :
							-1;
			}
		}
	},

	propFix: {
		"for": "htmlFor",
		"class": "className"
	}
} );

// Support: IE <=11 only
// Accessing the selectedIndex property
// forces the browser to respect setting selected
// on the option
// The getter ensures a default option is selected
// when in an optgroup
if ( !support.optSelected ) {
	jQuery.propHooks.selected = {
		get: function( elem ) {
			var parent = elem.parentNode;
			if ( parent && parent.parentNode ) {
				parent.parentNode.selectedIndex;
			}
			return null;
		},
		set: function( elem ) {
			var parent = elem.parentNode;
			if ( parent ) {
				parent.selectedIndex;

				if ( parent.parentNode ) {
					parent.parentNode.selectedIndex;
				}
			}
		}
	};
}

jQuery.each( [
	"tabIndex",
	"readOnly",
	"maxLength",
	"cellSpacing",
	"cellPadding",
	"rowSpan",
	"colSpan",
	"useMap",
	"frameBorder",
	"contentEditable"
], function() {
	jQuery.propFix[ this.toLowerCase() ] = this;
} );




var rclass = /[\t\r\n\f]/g;

function getClass( elem ) {
	return elem.getAttribute && elem.getAttribute( "class" ) || "";
}

jQuery.fn.extend( {
	addClass: function( value ) {
		var classes, elem, cur, curValue, clazz, j, finalValue,
			i = 0;

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		if ( typeof value === "string" && value ) {
			classes = value.match( rnotwhite ) || [];

			while ( ( elem = this[ i++ ] ) ) {
				curValue = getClass( elem );
				cur = elem.nodeType === 1 &&
					( " " + curValue + " " ).replace( rclass, " " );

				if ( cur ) {
					j = 0;
					while ( ( clazz = classes[ j++ ] ) ) {
						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
							cur += clazz + " ";
						}
					}

					// Only assign if different to avoid unneeded rendering.
					finalValue = jQuery.trim( cur );
					if ( curValue !== finalValue ) {
						elem.setAttribute( "class", finalValue );
					}
				}
			}
		}

		return this;
	},

	removeClass: function( value ) {
		var classes, elem, cur, curValue, clazz, j, finalValue,
			i = 0;

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( j ) {
				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
			} );
		}

		if ( !arguments.length ) {
			return this.attr( "class", "" );
		}

		if ( typeof value === "string" && value ) {
			classes = value.match( rnotwhite ) || [];

			while ( ( elem = this[ i++ ] ) ) {
				curValue = getClass( elem );

				// This expression is here for better compressibility (see addClass)
				cur = elem.nodeType === 1 &&
					( " " + curValue + " " ).replace( rclass, " " );

				if ( cur ) {
					j = 0;
					while ( ( clazz = classes[ j++ ] ) ) {

						// Remove *all* instances
						while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
							cur = cur.replace( " " + clazz + " ", " " );
						}
					}

					// Only assign if different to avoid unneeded rendering.
					finalValue = jQuery.trim( cur );
					if ( curValue !== finalValue ) {
						elem.setAttribute( "class", finalValue );
					}
				}
			}
		}

		return this;
	},

	toggleClass: function( value, stateVal ) {
		var type = typeof value;

		if ( typeof stateVal === "boolean" && type === "string" ) {
			return stateVal ? this.addClass( value ) : this.removeClass( value );
		}

		if ( jQuery.isFunction( value ) ) {
			return this.each( function( i ) {
				jQuery( this ).toggleClass(
					value.call( this, i, getClass( this ), stateVal ),
					stateVal
				);
			} );
		}

		return this.each( function() {
			var className, i, self, classNames;

			if ( type === "string" ) {

				// Toggle individual class names
				i = 0;
				self = jQuery( this );
				classNames = value.match( rnotwhite ) || [];

				while ( ( className = classNames[ i++ ] ) ) {

					// Check each className given, space separated list
					if ( self.hasClass( className ) ) {
						self.removeClass( className );
					} else {
						self.addClass( className );
					}
				}

			// Toggle whole class name
			} else if ( value === undefined || type === "boolean" ) {
				className = getClass( this );
				if ( className ) {

					// Store className if set
					dataPriv.set( this, "__className__", className );
				}

				// If the element has a class name or if we're passed `false`,
				// then remove the whole classname (if there was one, the above saved it).
				// Otherwise bring back whatever was previously saved (if anything),
				// falling back to the empty string if nothing was stored.
				if ( this.setAttribute ) {
					this.setAttribute( "class",
						className || value === false ?
						"" :
						dataPriv.get( this, "__className__" ) || ""
					);
				}
			}
		} );
	},

	hasClass: function( selector ) {
		var className, elem,
			i = 0;

		className = " " + selector + " ";
		while ( ( elem = this[ i++ ] ) ) {
			if ( elem.nodeType === 1 &&
				( " " + getClass( elem ) + " " ).replace( rclass, " " )
					.indexOf( className ) > -1
			) {
				return true;
			}
		}

		return false;
	}
} );




var rreturn = /\r/g,
	rspaces = /[\x20\t\r\n\f]+/g;

jQuery.fn.extend( {
	val: function( value ) {
		var hooks, ret, isFunction,
			elem = this[ 0 ];

		if ( !arguments.length ) {
			if ( elem ) {
				hooks = jQuery.valHooks[ elem.type ] ||
					jQuery.valHooks[ elem.nodeName.toLowerCase() ];

				if ( hooks &&
					"get" in hooks &&
					( ret = hooks.get( elem, "value" ) ) !== undefined
				) {
					return ret;
				}

				ret = elem.value;

				return typeof ret === "string" ?

					// Handle most common string cases
					ret.replace( rreturn, "" ) :

					// Handle cases where value is null/undef or number
					ret == null ? "" : ret;
			}

			return;
		}

		isFunction = jQuery.isFunction( value );

		return this.each( function( i ) {
			var val;

			if ( this.nodeType !== 1 ) {
				return;
			}

			if ( isFunction ) {
				val = value.call( this, i, jQuery( this ).val() );
			} else {
				val = value;
			}

			// Treat null/undefined as ""; convert numbers to string
			if ( val == null ) {
				val = "";

			} else if ( typeof val === "number" ) {
				val += "";

			} else if ( jQuery.isArray( val ) ) {
				val = jQuery.map( val, function( value ) {
					return value == null ? "" : value + "";
				} );
			}

			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];

			// If set returns undefined, fall back to normal setting
			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
				this.value = val;
			}
		} );
	}
} );

jQuery.extend( {
	valHooks: {
		option: {
			get: function( elem ) {

				var val = jQuery.find.attr( elem, "value" );
				return val != null ?
					val :

					// Support: IE10-11+
					// option.text throws exceptions (#14686, #14858)
					// Strip and collapse whitespace
					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
					jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
			}
		},
		select: {
			get: function( elem ) {
				var value, option,
					options = elem.options,
					index = elem.selectedIndex,
					one = elem.type === "select-one" || index < 0,
					values = one ? null : [],
					max = one ? index + 1 : options.length,
					i = index < 0 ?
						max :
						one ? index : 0;

				// Loop through all the selected options
				for ( ; i < max; i++ ) {
					option = options[ i ];

					// IE8-9 doesn't update selected after form reset (#2551)
					if ( ( option.selected || i === index ) &&

							// Don't return options that are disabled or in a disabled optgroup
							( support.optDisabled ?
								!option.disabled : option.getAttribute( "disabled" ) === null ) &&
							( !option.parentNode.disabled ||
								!jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {

						// Get the specific value for the option
						value = jQuery( option ).val();

						// We don't need an array for one selects
						if ( one ) {
							return value;
						}

						// Multi-Selects return an array
						values.push( value );
					}
				}

				return values;
			},

			set: function( elem, value ) {
				var optionSet, option,
					options = elem.options,
					values = jQuery.makeArray( value ),
					i = options.length;

				while ( i-- ) {
					option = options[ i ];
					if ( option.selected =
						jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
					) {
						optionSet = true;
					}
				}

				// Force browsers to behave consistently when non-matching value is set
				if ( !optionSet ) {
					elem.selectedIndex = -1;
				}
				return values;
			}
		}
	}
} );

// Radios and checkboxes getter/setter
jQuery.each( [ "radio", "checkbox" ], function() {
	jQuery.valHooks[ this ] = {
		set: function( elem, value ) {
			if ( jQuery.isArray( value ) ) {
				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
			}
		}
	};
	if ( !support.checkOn ) {
		jQuery.valHooks[ this ].get = function( elem ) {
			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
		};
	}
} );




// Return jQuery for attributes-only inclusion


var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;

jQuery.extend( jQuery.event, {

	trigger: function( event, data, elem, onlyHandlers ) {

		var i, cur, tmp, bubbleType, ontype, handle, special,
			eventPath = [ elem || document ],
			type = hasOwn.call( event, "type" ) ? event.type : event,
			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];

		cur = tmp = elem = elem || document;

		// Don't do events on text and comment nodes
		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
			return;
		}

		// focus/blur morphs to focusin/out; ensure we're not firing them right now
		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
			return;
		}

		if ( type.indexOf( "." ) > -1 ) {

			// Namespaced trigger; create a regexp to match event type in handle()
			namespaces = type.split( "." );
			type = namespaces.shift();
			namespaces.sort();
		}
		ontype = type.indexOf( ":" ) < 0 && "on" + type;

		// Caller can pass in a jQuery.Event object, Object, or just an event type string
		event = event[ jQuery.expando ] ?
			event :
			new jQuery.Event( type, typeof event === "object" && event );

		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
		event.isTrigger = onlyHandlers ? 2 : 3;
		event.namespace = namespaces.join( "." );
		event.rnamespace = event.namespace ?
			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
			null;

		// Clean up the event in case it is being reused
		event.result = undefined;
		if ( !event.target ) {
			event.target = elem;
		}

		// Clone any incoming data and prepend the event, creating the handler arg list
		data = data == null ?
			[ event ] :
			jQuery.makeArray( data, [ event ] );

		// Allow special events to draw outside the lines
		special = jQuery.event.special[ type ] || {};
		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
			return;
		}

		// Determine event propagation path in advance, per W3C events spec (#9951)
		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {

			bubbleType = special.delegateType || type;
			if ( !rfocusMorph.test( bubbleType + type ) ) {
				cur = cur.parentNode;
			}
			for ( ; cur; cur = cur.parentNode ) {
				eventPath.push( cur );
				tmp = cur;
			}

			// Only add window if we got to document (e.g., not plain obj or detached DOM)
			if ( tmp === ( elem.ownerDocument || document ) ) {
				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
			}
		}

		// Fire handlers on the event path
		i = 0;
		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {

			event.type = i > 1 ?
				bubbleType :
				special.bindType || type;

			// jQuery handler
			handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
				dataPriv.get( cur, "handle" );
			if ( handle ) {
				handle.apply( cur, data );
			}

			// Native handler
			handle = ontype && cur[ ontype ];
			if ( handle && handle.apply && acceptData( cur ) ) {
				event.result = handle.apply( cur, data );
				if ( event.result === false ) {
					event.preventDefault();
				}
			}
		}
		event.type = type;

		// If nobody prevented the default action, do it now
		if ( !onlyHandlers && !event.isDefaultPrevented() ) {

			if ( ( !special._default ||
				special._default.apply( eventPath.pop(), data ) === false ) &&
				acceptData( elem ) ) {

				// Call a native DOM method on the target with the same name name as the event.
				// Don't do default actions on window, that's where global variables be (#6170)
				if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {

					// Don't re-trigger an onFOO event when we call its FOO() method
					tmp = elem[ ontype ];

					if ( tmp ) {
						elem[ ontype ] = null;
					}

					// Prevent re-triggering of the same event, since we already bubbled it above
					jQuery.event.triggered = type;
					elem[ type ]();
					jQuery.event.triggered = undefined;

					if ( tmp ) {
						elem[ ontype ] = tmp;
					}
				}
			}
		}

		return event.result;
	},

	// Piggyback on a donor event to simulate a different one
	// Used only for `focus(in | out)` events
	simulate: function( type, elem, event ) {
		var e = jQuery.extend(
			new jQuery.Event(),
			event,
			{
				type: type,
				isSimulated: true
			}
		);

		jQuery.event.trigger( e, null, elem );
	}

} );

jQuery.fn.extend( {

	trigger: function( type, data ) {
		return this.each( function() {
			jQuery.event.trigger( type, data, this );
		} );
	},
	triggerHandler: function( type, data ) {
		var elem = this[ 0 ];
		if ( elem ) {
			return jQuery.event.trigger( type, data, elem, true );
		}
	}
} );


jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " +
	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
	"change select submit keydown keypress keyup error contextmenu" ).split( " " ),
	function( i, name ) {

	// Handle event binding
	jQuery.fn[ name ] = function( data, fn ) {
		return arguments.length > 0 ?
			this.on( name, null, data, fn ) :
			this.trigger( name );
	};
} );

jQuery.fn.extend( {
	hover: function( fnOver, fnOut ) {
		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
	}
} );




support.focusin = "onfocusin" in window;


// Support: Firefox
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome, Safari
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
	jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {

		// Attach a single capturing handler on the document while someone wants focusin/focusout
		var handler = function( event ) {
			jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
		};

		jQuery.event.special[ fix ] = {
			setup: function() {
				var doc = this.ownerDocument || this,
					attaches = dataPriv.access( doc, fix );

				if ( !attaches ) {
					doc.addEventListener( orig, handler, true );
				}
				dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
			},
			teardown: function() {
				var doc = this.ownerDocument || this,
					attaches = dataPriv.access( doc, fix ) - 1;

				if ( !attaches ) {
					doc.removeEventListener( orig, handler, true );
					dataPriv.remove( doc, fix );

				} else {
					dataPriv.access( doc, fix, attaches );
				}
			}
		};
	} );
}
var location = window.location;

var nonce = jQuery.now();

var rquery = ( /\?/ );



// Support: Android 2.3
// Workaround failure to string-cast null input
jQuery.parseJSON = function( data ) {
	return JSON.parse( data + "" );
};


// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
	var xml;
	if ( !data || typeof data !== "string" ) {
		return null;
	}

	// Support: IE9
	try {
		xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
	} catch ( e ) {
		xml = undefined;
	}

	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
		jQuery.error( "Invalid XML: " + data );
	}
	return xml;
};


var
	rhash = /#.*$/,
	rts = /([?&])_=[^&]*/,
	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,

	// #7653, #8125, #8152: local protocol detection
	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
	rnoContent = /^(?:GET|HEAD)$/,
	rprotocol = /^\/\//,

	/* Prefilters
	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
	 * 2) These are called:
	 *    - BEFORE asking for a transport
	 *    - AFTER param serialization (s.data is a string if s.processData is true)
	 * 3) key is the dataType
	 * 4) the catchall symbol "*" can be used
	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
	 */
	prefilters = {},

	/* Transports bindings
	 * 1) key is the dataType
	 * 2) the catchall symbol "*" can be used
	 * 3) selection will start with transport dataType and THEN go to "*" if needed
	 */
	transports = {},

	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
	allTypes = "*/".concat( "*" ),

	// Anchor tag for parsing the document origin
	originAnchor = document.createElement( "a" );
	originAnchor.href = location.href;

// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {

	// dataTypeExpression is optional and defaults to "*"
	return function( dataTypeExpression, func ) {

		if ( typeof dataTypeExpression !== "string" ) {
			func = dataTypeExpression;
			dataTypeExpression = "*";
		}

		var dataType,
			i = 0,
			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];

		if ( jQuery.isFunction( func ) ) {

			// For each dataType in the dataTypeExpression
			while ( ( dataType = dataTypes[ i++ ] ) ) {

				// Prepend if requested
				if ( dataType[ 0 ] === "+" ) {
					dataType = dataType.slice( 1 ) || "*";
					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );

				// Otherwise append
				} else {
					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
				}
			}
		}
	};
}

// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {

	var inspected = {},
		seekingTransport = ( structure === transports );

	function inspect( dataType ) {
		var selected;
		inspected[ dataType ] = true;
		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
			if ( typeof dataTypeOrTransport === "string" &&
				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {

				options.dataTypes.unshift( dataTypeOrTransport );
				inspect( dataTypeOrTransport );
				return false;
			} else if ( seekingTransport ) {
				return !( selected = dataTypeOrTransport );
			}
		} );
		return selected;
	}

	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}

// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
	var key, deep,
		flatOptions = jQuery.ajaxSettings.flatOptions || {};

	for ( key in src ) {
		if ( src[ key ] !== undefined ) {
			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
		}
	}
	if ( deep ) {
		jQuery.extend( true, target, deep );
	}

	return target;
}

/* Handles responses to an ajax request:
 * - finds the right dataType (mediates between content-type and expected dataType)
 * - returns the corresponding response
 */
function ajaxHandleResponses( s, jqXHR, responses ) {

	var ct, type, finalDataType, firstDataType,
		contents = s.contents,
		dataTypes = s.dataTypes;

	// Remove auto dataType and get content-type in the process
	while ( dataTypes[ 0 ] === "*" ) {
		dataTypes.shift();
		if ( ct === undefined ) {
			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
		}
	}

	// Check if we're dealing with a known content-type
	if ( ct ) {
		for ( type in contents ) {
			if ( contents[ type ] && contents[ type ].test( ct ) ) {
				dataTypes.unshift( type );
				break;
			}
		}
	}

	// Check to see if we have a response for the expected dataType
	if ( dataTypes[ 0 ] in responses ) {
		finalDataType = dataTypes[ 0 ];
	} else {

		// Try convertible dataTypes
		for ( type in responses ) {
			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
				finalDataType = type;
				break;
			}
			if ( !firstDataType ) {
				firstDataType = type;
			}
		}

		// Or just use first one
		finalDataType = finalDataType || firstDataType;
	}

	// If we found a dataType
	// We add the dataType to the list if needed
	// and return the corresponding response
	if ( finalDataType ) {
		if ( finalDataType !== dataTypes[ 0 ] ) {
			dataTypes.unshift( finalDataType );
		}
		return responses[ finalDataType ];
	}
}

/* Chain conversions given the request and the original response
 * Also sets the responseXXX fields on the jqXHR instance
 */
function ajaxConvert( s, response, jqXHR, isSuccess ) {
	var conv2, current, conv, tmp, prev,
		converters = {},

		// Work with a copy of dataTypes in case we need to modify it for conversion
		dataTypes = s.dataTypes.slice();

	// Create converters map with lowercased keys
	if ( dataTypes[ 1 ] ) {
		for ( conv in s.converters ) {
			converters[ conv.toLowerCase() ] = s.converters[ conv ];
		}
	}

	current = dataTypes.shift();

	// Convert to each sequential dataType
	while ( current ) {

		if ( s.responseFields[ current ] ) {
			jqXHR[ s.responseFields[ current ] ] = response;
		}

		// Apply the dataFilter if provided
		if ( !prev && isSuccess && s.dataFilter ) {
			response = s.dataFilter( response, s.dataType );
		}

		prev = current;
		current = dataTypes.shift();

		if ( current ) {

		// There's only work to do if current dataType is non-auto
			if ( current === "*" ) {

				current = prev;

			// Convert response if prev dataType is non-auto and differs from current
			} else if ( prev !== "*" && prev !== current ) {

				// Seek a direct converter
				conv = converters[ prev + " " + current ] || converters[ "* " + current ];

				// If none found, seek a pair
				if ( !conv ) {
					for ( conv2 in converters ) {

						// If conv2 outputs current
						tmp = conv2.split( " " );
						if ( tmp[ 1 ] === current ) {

							// If prev can be converted to accepted input
							conv = converters[ prev + " " + tmp[ 0 ] ] ||
								converters[ "* " + tmp[ 0 ] ];
							if ( conv ) {

								// Condense equivalence converters
								if ( conv === true ) {
									conv = converters[ conv2 ];

								// Otherwise, insert the intermediate dataType
								} else if ( converters[ conv2 ] !== true ) {
									current = tmp[ 0 ];
									dataTypes.unshift( tmp[ 1 ] );
								}
								break;
							}
						}
					}
				}

				// Apply converter (if not an equivalence)
				if ( conv !== true ) {

					// Unless errors are allowed to bubble, catch and return them
					if ( conv && s.throws ) {
						response = conv( response );
					} else {
						try {
							response = conv( response );
						} catch ( e ) {
							return {
								state: "parsererror",
								error: conv ? e : "No conversion from " + prev + " to " + current
							};
						}
					}
				}
			}
		}
	}

	return { state: "success", data: response };
}

jQuery.extend( {

	// Counter for holding the number of active queries
	active: 0,

	// Last-Modified header cache for next request
	lastModified: {},
	etag: {},

	ajaxSettings: {
		url: location.href,
		type: "GET",
		isLocal: rlocalProtocol.test( location.protocol ),
		global: true,
		processData: true,
		async: true,
		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
		/*
		timeout: 0,
		data: null,
		dataType: null,
		username: null,
		password: null,
		cache: null,
		throws: false,
		traditional: false,
		headers: {},
		*/

		accepts: {
			"*": allTypes,
			text: "text/plain",
			html: "text/html",
			xml: "application/xml, text/xml",
			json: "application/json, text/javascript"
		},

		contents: {
			xml: /\bxml\b/,
			html: /\bhtml/,
			json: /\bjson\b/
		},

		responseFields: {
			xml: "responseXML",
			text: "responseText",
			json: "responseJSON"
		},

		// Data converters
		// Keys separate source (or catchall "*") and destination types with a single space
		converters: {

			// Convert anything to text
			"* text": String,

			// Text to html (true = no transformation)
			"text html": true,

			// Evaluate text as a json expression
			"text json": jQuery.parseJSON,

			// Parse text as xml
			"text xml": jQuery.parseXML
		},

		// For options that shouldn't be deep extended:
		// you can add your own custom options here if
		// and when you create one that shouldn't be
		// deep extended (see ajaxExtend)
		flatOptions: {
			url: true,
			context: true
		}
	},

	// Creates a full fledged settings object into target
	// with both ajaxSettings and settings fields.
	// If target is omitted, writes into ajaxSettings.
	ajaxSetup: function( target, settings ) {
		return settings ?

			// Building a settings object
			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :

			// Extending ajaxSettings
			ajaxExtend( jQuery.ajaxSettings, target );
	},

	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
	ajaxTransport: addToPrefiltersOrTransports( transports ),

	// Main method
	ajax: function( url, options ) {

		// If url is an object, simulate pre-1.5 signature
		if ( typeof url === "object" ) {
			options = url;
			url = undefined;
		}

		// Force options to be an object
		options = options || {};

		var transport,

			// URL without anti-cache param
			cacheURL,

			// Response headers
			responseHeadersString,
			responseHeaders,

			// timeout handle
			timeoutTimer,

			// Url cleanup var
			urlAnchor,

			// To know if global events are to be dispatched
			fireGlobals,

			// Loop variable
			i,

			// Create the final options object
			s = jQuery.ajaxSetup( {}, options ),

			// Callbacks context
			callbackContext = s.context || s,

			// Context for global events is callbackContext if it is a DOM node or jQuery collection
			globalEventContext = s.context &&
				( callbackContext.nodeType || callbackContext.jquery ) ?
					jQuery( callbackContext ) :
					jQuery.event,

			// Deferreds
			deferred = jQuery.Deferred(),
			completeDeferred = jQuery.Callbacks( "once memory" ),

			// Status-dependent callbacks
			statusCode = s.statusCode || {},

			// Headers (they are sent all at once)
			requestHeaders = {},
			requestHeadersNames = {},

			// The jqXHR state
			state = 0,

			// Default abort message
			strAbort = "canceled",

			// Fake xhr
			jqXHR = {
				readyState: 0,

				// Builds headers hashtable if needed
				getResponseHeader: function( key ) {
					var match;
					if ( state === 2 ) {
						if ( !responseHeaders ) {
							responseHeaders = {};
							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
								responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
							}
						}
						match = responseHeaders[ key.toLowerCase() ];
					}
					return match == null ? null : match;
				},

				// Raw string
				getAllResponseHeaders: function() {
					return state === 2 ? responseHeadersString : null;
				},

				// Caches the header
				setRequestHeader: function( name, value ) {
					var lname = name.toLowerCase();
					if ( !state ) {
						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
						requestHeaders[ name ] = value;
					}
					return this;
				},

				// Overrides response content-type header
				overrideMimeType: function( type ) {
					if ( !state ) {
						s.mimeType = type;
					}
					return this;
				},

				// Status-dependent callbacks
				statusCode: function( map ) {
					var code;
					if ( map ) {
						if ( state < 2 ) {
							for ( code in map ) {

								// Lazy-add the new callback in a way that preserves old ones
								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
							}
						} else {

							// Execute the appropriate callbacks
							jqXHR.always( map[ jqXHR.status ] );
						}
					}
					return this;
				},

				// Cancel the request
				abort: function( statusText ) {
					var finalText = statusText || strAbort;
					if ( transport ) {
						transport.abort( finalText );
					}
					done( 0, finalText );
					return this;
				}
			};

		// Attach deferreds
		deferred.promise( jqXHR ).complete = completeDeferred.add;
		jqXHR.success = jqXHR.done;
		jqXHR.error = jqXHR.fail;

		// Remove hash character (#7531: and string promotion)
		// Add protocol if not provided (prefilters might expect it)
		// Handle falsy url in the settings object (#10093: consistency with old signature)
		// We also use the url parameter if available
		s.url = ( ( url || s.url || location.href ) + "" ).replace( rhash, "" )
			.replace( rprotocol, location.protocol + "//" );

		// Alias method option to type as per ticket #12004
		s.type = options.method || options.type || s.method || s.type;

		// Extract dataTypes list
		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];

		// A cross-domain request is in order when the origin doesn't match the current origin.
		if ( s.crossDomain == null ) {
			urlAnchor = document.createElement( "a" );

			// Support: IE8-11+
			// IE throws exception if url is malformed, e.g. http://example.com:80x/
			try {
				urlAnchor.href = s.url;

				// Support: IE8-11+
				// Anchor's host property isn't correctly set when s.url is relative
				urlAnchor.href = urlAnchor.href;
				s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
					urlAnchor.protocol + "//" + urlAnchor.host;
			} catch ( e ) {

				// If there is an error parsing the URL, assume it is crossDomain,
				// it can be rejected by the transport if it is invalid
				s.crossDomain = true;
			}
		}

		// Convert data if not already a string
		if ( s.data && s.processData && typeof s.data !== "string" ) {
			s.data = jQuery.param( s.data, s.traditional );
		}

		// Apply prefilters
		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );

		// If request was aborted inside a prefilter, stop there
		if ( state === 2 ) {
			return jqXHR;
		}

		// We can fire global events as of now if asked to
		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
		fireGlobals = jQuery.event && s.global;

		// Watch for a new set of requests
		if ( fireGlobals && jQuery.active++ === 0 ) {
			jQuery.event.trigger( "ajaxStart" );
		}

		// Uppercase the type
		s.type = s.type.toUpperCase();

		// Determine if request has content
		s.hasContent = !rnoContent.test( s.type );

		// Save the URL in case we're toying with the If-Modified-Since
		// and/or If-None-Match header later on
		cacheURL = s.url;

		// More options handling for requests with no content
		if ( !s.hasContent ) {

			// If data is available, append data to url
			if ( s.data ) {
				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );

				// #9682: remove data so that it's not used in an eventual retry
				delete s.data;
			}

			// Add anti-cache in url if needed
			if ( s.cache === false ) {
				s.url = rts.test( cacheURL ) ?

					// If there is already a '_' parameter, set its value
					cacheURL.replace( rts, "$1_=" + nonce++ ) :

					// Otherwise add one to the end
					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
			}
		}

		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
		if ( s.ifModified ) {
			if ( jQuery.lastModified[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
			}
			if ( jQuery.etag[ cacheURL ] ) {
				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
			}
		}

		// Set the correct header, if data is being sent
		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
			jqXHR.setRequestHeader( "Content-Type", s.contentType );
		}

		// Set the Accepts header for the server, depending on the dataType
		jqXHR.setRequestHeader(
			"Accept",
			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
				s.accepts[ s.dataTypes[ 0 ] ] +
					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
				s.accepts[ "*" ]
		);

		// Check for headers option
		for ( i in s.headers ) {
			jqXHR.setRequestHeader( i, s.headers[ i ] );
		}

		// Allow custom headers/mimetypes and early abort
		if ( s.beforeSend &&
			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {

			// Abort if not done already and return
			return jqXHR.abort();
		}

		// Aborting is no longer a cancellation
		strAbort = "abort";

		// Install callbacks on deferreds
		for ( i in { success: 1, error: 1, complete: 1 } ) {
			jqXHR[ i ]( s[ i ] );
		}

		// Get transport
		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );

		// If no transport, we auto-abort
		if ( !transport ) {
			done( -1, "No Transport" );
		} else {
			jqXHR.readyState = 1;

			// Send global event
			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
			}

			// If request was aborted inside ajaxSend, stop there
			if ( state === 2 ) {
				return jqXHR;
			}

			// Timeout
			if ( s.async && s.timeout > 0 ) {
				timeoutTimer = window.setTimeout( function() {
					jqXHR.abort( "timeout" );
				}, s.timeout );
			}

			try {
				state = 1;
				transport.send( requestHeaders, done );
			} catch ( e ) {

				// Propagate exception as error if not done
				if ( state < 2 ) {
					done( -1, e );

				// Simply rethrow otherwise
				} else {
					throw e;
				}
			}
		}

		// Callback for when everything is done
		function done( status, nativeStatusText, responses, headers ) {
			var isSuccess, success, error, response, modified,
				statusText = nativeStatusText;

			// Called once
			if ( state === 2 ) {
				return;
			}

			// State is "done" now
			state = 2;

			// Clear timeout if it exists
			if ( timeoutTimer ) {
				window.clearTimeout( timeoutTimer );
			}

			// Dereference transport for early garbage collection
			// (no matter how long the jqXHR object will be used)
			transport = undefined;

			// Cache response headers
			responseHeadersString = headers || "";

			// Set readyState
			jqXHR.readyState = status > 0 ? 4 : 0;

			// Determine if successful
			isSuccess = status >= 200 && status < 300 || status === 304;

			// Get response data
			if ( responses ) {
				response = ajaxHandleResponses( s, jqXHR, responses );
			}

			// Convert no matter what (that way responseXXX fields are always set)
			response = ajaxConvert( s, response, jqXHR, isSuccess );

			// If successful, handle type chaining
			if ( isSuccess ) {

				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
				if ( s.ifModified ) {
					modified = jqXHR.getResponseHeader( "Last-Modified" );
					if ( modified ) {
						jQuery.lastModified[ cacheURL ] = modified;
					}
					modified = jqXHR.getResponseHeader( "etag" );
					if ( modified ) {
						jQuery.etag[ cacheURL ] = modified;
					}
				}

				// if no content
				if ( status === 204 || s.type === "HEAD" ) {
					statusText = "nocontent";

				// if not modified
				} else if ( status === 304 ) {
					statusText = "notmodified";

				// If we have data, let's convert it
				} else {
					statusText = response.state;
					success = response.data;
					error = response.error;
					isSuccess = !error;
				}
			} else {

				// Extract error from statusText and normalize for non-aborts
				error = statusText;
				if ( status || !statusText ) {
					statusText = "error";
					if ( status < 0 ) {
						status = 0;
					}
				}
			}

			// Set data for the fake xhr object
			jqXHR.status = status;
			jqXHR.statusText = ( nativeStatusText || statusText ) + "";

			// Success/Error
			if ( isSuccess ) {
				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
			} else {
				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
			}

			// Status-dependent callbacks
			jqXHR.statusCode( statusCode );
			statusCode = undefined;

			if ( fireGlobals ) {
				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
					[ jqXHR, s, isSuccess ? success : error ] );
			}

			// Complete
			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );

			if ( fireGlobals ) {
				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );

				// Handle the global AJAX counter
				if ( !( --jQuery.active ) ) {
					jQuery.event.trigger( "ajaxStop" );
				}
			}
		}

		return jqXHR;
	},

	getJSON: function( url, data, callback ) {
		return jQuery.get( url, data, callback, "json" );
	},

	getScript: function( url, callback ) {
		return jQuery.get( url, undefined, callback, "script" );
	}
} );

jQuery.each( [ "get", "post" ], function( i, method ) {
	jQuery[ method ] = function( url, data, callback, type ) {

		// Shift arguments if data argument was omitted
		if ( jQuery.isFunction( data ) ) {
			type = type || callback;
			callback = data;
			data = undefined;
		}

		// The url can be an options object (which then must have .url)
		return jQuery.ajax( jQuery.extend( {
			url: url,
			type: method,
			dataType: type,
			data: data,
			success: callback
		}, jQuery.isPlainObject( url ) && url ) );
	};
} );


jQuery._evalUrl = function( url ) {
	return jQuery.ajax( {
		url: url,

		// Make this explicit, since user can override this through ajaxSetup (#11264)
		type: "GET",
		dataType: "script",
		async: false,
		global: false,
		"throws": true
	} );
};


jQuery.fn.extend( {
	wrapAll: function( html ) {
		var wrap;

		if ( jQuery.isFunction( html ) ) {
			return this.each( function( i ) {
				jQuery( this ).wrapAll( html.call( this, i ) );
			} );
		}

		if ( this[ 0 ] ) {

			// The elements to wrap the target around
			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );

			if ( this[ 0 ].parentNode ) {
				wrap.insertBefore( this[ 0 ] );
			}

			wrap.map( function() {
				var elem = this;

				while ( elem.firstElementChild ) {
					elem = elem.firstElementChild;
				}

				return elem;
			} ).append( this );
		}

		return this;
	},

	wrapInner: function( html ) {
		if ( jQuery.isFunction( html ) ) {
			return this.each( function( i ) {
				jQuery( this ).wrapInner( html.call( this, i ) );
			} );
		}

		return this.each( function() {
			var self = jQuery( this ),
				contents = self.contents();

			if ( contents.length ) {
				contents.wrapAll( html );

			} else {
				self.append( html );
			}
		} );
	},

	wrap: function( html ) {
		var isFunction = jQuery.isFunction( html );

		return this.each( function( i ) {
			jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
		} );
	},

	unwrap: function() {
		return this.parent().each( function() {
			if ( !jQuery.nodeName( this, "body" ) ) {
				jQuery( this ).replaceWith( this.childNodes );
			}
		} ).end();
	}
} );


jQuery.expr.filters.hidden = function( elem ) {
	return !jQuery.expr.filters.visible( elem );
};
jQuery.expr.filters.visible = function( elem ) {

	// Support: Opera <= 12.12
	// Opera reports offsetWidths and offsetHeights less than zero on some elements
	// Use OR instead of AND as the element is not visible if either is true
	// See tickets #10406 and #13132
	return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0;
};




var r20 = /%20/g,
	rbracket = /\[\]$/,
	rCRLF = /\r?\n/g,
	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
	rsubmittable = /^(?:input|select|textarea|keygen)/i;

function buildParams( prefix, obj, traditional, add ) {
	var name;

	if ( jQuery.isArray( obj ) ) {

		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {

				// Treat each array item as a scalar.
				add( prefix, v );

			} else {

				// Item is non-scalar (array or object), encode its numeric index.
				buildParams(
					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
					v,
					traditional,
					add
				);
			}
		} );

	} else if ( !traditional && jQuery.type( obj ) === "object" ) {

		// Serialize object item.
		for ( name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {

		// Serialize scalar item.
		add( prefix, obj );
	}
}

// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
	var prefix,
		s = [],
		add = function( key, value ) {

			// If value is a function, invoke it and return its value
			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
		};

	// Set traditional to true for jQuery <= 1.3.2 behavior.
	if ( traditional === undefined ) {
		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
	}

	// If an array was passed in, assume that it is an array of form elements.
	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {

		// Serialize the form elements
		jQuery.each( a, function() {
			add( this.name, this.value );
		} );

	} else {

		// If traditional, encode the "old" way (the way 1.3.2 or older
		// did it), otherwise encode params recursively.
		for ( prefix in a ) {
			buildParams( prefix, a[ prefix ], traditional, add );
		}
	}

	// Return the resulting serialization
	return s.join( "&" ).replace( r20, "+" );
};

jQuery.fn.extend( {
	serialize: function() {
		return jQuery.param( this.serializeArray() );
	},
	serializeArray: function() {
		return this.map( function() {

			// Can add propHook for "elements" to filter or add form elements
			var elements = jQuery.prop( this, "elements" );
			return elements ? jQuery.makeArray( elements ) : this;
		} )
		.filter( function() {
			var type = this.type;

			// Use .is( ":disabled" ) so that fieldset[disabled] works
			return this.name && !jQuery( this ).is( ":disabled" ) &&
				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
				( this.checked || !rcheckableType.test( type ) );
		} )
		.map( function( i, elem ) {
			var val = jQuery( this ).val();

			return val == null ?
				null :
				jQuery.isArray( val ) ?
					jQuery.map( val, function( val ) {
						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
					} ) :
					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
		} ).get();
	}
} );


jQuery.ajaxSettings.xhr = function() {
	try {
		return new window.XMLHttpRequest();
	} catch ( e ) {}
};

var xhrSuccessStatus = {

		// File protocol always yields status code 0, assume 200
		0: 200,

		// Support: IE9
		// #1450: sometimes IE returns 1223 when it should be 204
		1223: 204
	},
	xhrSupported = jQuery.ajaxSettings.xhr();

support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
support.ajax = xhrSupported = !!xhrSupported;

jQuery.ajaxTransport( function( options ) {
	var callback, errorCallback;

	// Cross domain only allowed if supported through XMLHttpRequest
	if ( support.cors || xhrSupported && !options.crossDomain ) {
		return {
			send: function( headers, complete ) {
				var i,
					xhr = options.xhr();

				xhr.open(
					options.type,
					options.url,
					options.async,
					options.username,
					options.password
				);

				// Apply custom fields if provided
				if ( options.xhrFields ) {
					for ( i in options.xhrFields ) {
						xhr[ i ] = options.xhrFields[ i ];
					}
				}

				// Override mime type if needed
				if ( options.mimeType && xhr.overrideMimeType ) {
					xhr.overrideMimeType( options.mimeType );
				}

				// X-Requested-With header
				// For cross-domain requests, seeing as conditions for a preflight are
				// akin to a jigsaw puzzle, we simply never set it to be sure.
				// (it can always be set on a per-request basis or even using ajaxSetup)
				// For same-domain requests, won't change header if already provided.
				if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
					headers[ "X-Requested-With" ] = "XMLHttpRequest";
				}

				// Set headers
				for ( i in headers ) {
					xhr.setRequestHeader( i, headers[ i ] );
				}

				// Callback
				callback = function( type ) {
					return function() {
						if ( callback ) {
							callback = errorCallback = xhr.onload =
								xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;

							if ( type === "abort" ) {
								xhr.abort();
							} else if ( type === "error" ) {

								// Support: IE9
								// On a manual native abort, IE9 throws
								// errors on any property access that is not readyState
								if ( typeof xhr.status !== "number" ) {
									complete( 0, "error" );
								} else {
									complete(

										// File: protocol always yields status 0; see #8605, #14207
										xhr.status,
										xhr.statusText
									);
								}
							} else {
								complete(
									xhrSuccessStatus[ xhr.status ] || xhr.status,
									xhr.statusText,

									// Support: IE9 only
									// IE9 has no XHR2 but throws on binary (trac-11426)
									// For XHR2 non-text, let the caller handle it (gh-2498)
									( xhr.responseType || "text" ) !== "text"  ||
									typeof xhr.responseText !== "string" ?
										{ binary: xhr.response } :
										{ text: xhr.responseText },
									xhr.getAllResponseHeaders()
								);
							}
						}
					};
				};

				// Listen to events
				xhr.onload = callback();
				errorCallback = xhr.onerror = callback( "error" );

				// Support: IE9
				// Use onreadystatechange to replace onabort
				// to handle uncaught aborts
				if ( xhr.onabort !== undefined ) {
					xhr.onabort = errorCallback;
				} else {
					xhr.onreadystatechange = function() {

						// Check readyState before timeout as it changes
						if ( xhr.readyState === 4 ) {

							// Allow onerror to be called first,
							// but that will not handle a native abort
							// Also, save errorCallback to a variable
							// as xhr.onerror cannot be accessed
							window.setTimeout( function() {
								if ( callback ) {
									errorCallback();
								}
							} );
						}
					};
				}

				// Create the abort callback
				callback = callback( "abort" );

				try {

					// Do send the request (this may raise an exception)
					xhr.send( options.hasContent && options.data || null );
				} catch ( e ) {

					// #14683: Only rethrow if this hasn't been notified as an error yet
					if ( callback ) {
						throw e;
					}
				}
			},

			abort: function() {
				if ( callback ) {
					callback();
				}
			}
		};
	}
} );




// Install script dataType
jQuery.ajaxSetup( {
	accepts: {
		script: "text/javascript, application/javascript, " +
			"application/ecmascript, application/x-ecmascript"
	},
	contents: {
		script: /\b(?:java|ecma)script\b/
	},
	converters: {
		"text script": function( text ) {
			jQuery.globalEval( text );
			return text;
		}
	}
} );

// Handle cache's special case and crossDomain
jQuery.ajaxPrefilter( "script", function( s ) {
	if ( s.cache === undefined ) {
		s.cache = false;
	}
	if ( s.crossDomain ) {
		s.type = "GET";
	}
} );

// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {

	// This transport only deals with cross domain requests
	if ( s.crossDomain ) {
		var script, callback;
		return {
			send: function( _, complete ) {
				script = jQuery( "<script>" ).prop( {
					charset: s.scriptCharset,
					src: s.url
				} ).on(
					"load error",
					callback = function( evt ) {
						script.remove();
						callback = null;
						if ( evt ) {
							complete( evt.type === "error" ? 404 : 200, evt.type );
						}
					}
				);

				// Use native DOM manipulation to avoid our domManip AJAX trickery
				document.head.appendChild( script[ 0 ] );
			},
			abort: function() {
				if ( callback ) {
					callback();
				}
			}
		};
	}
} );




var oldCallbacks = [],
	rjsonp = /(=)\?(?=&|$)|\?\?/;

// Default jsonp settings
jQuery.ajaxSetup( {
	jsonp: "callback",
	jsonpCallback: function() {
		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
		this[ callback ] = true;
		return callback;
	}
} );

// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {

	var callbackName, overwritten, responseContainer,
		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
			"url" :
			typeof s.data === "string" &&
				( s.contentType || "" )
					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
				rjsonp.test( s.data ) && "data"
		);

	// Handle iff the expected data type is "jsonp" or we have a parameter to set
	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {

		// Get callback name, remembering preexisting value associated with it
		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
			s.jsonpCallback() :
			s.jsonpCallback;

		// Insert callback into url or form data
		if ( jsonProp ) {
			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
		} else if ( s.jsonp !== false ) {
			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
		}

		// Use data converter to retrieve json after script execution
		s.converters[ "script json" ] = function() {
			if ( !responseContainer ) {
				jQuery.error( callbackName + " was not called" );
			}
			return responseContainer[ 0 ];
		};

		// Force json dataType
		s.dataTypes[ 0 ] = "json";

		// Install callback
		overwritten = window[ callbackName ];
		window[ callbackName ] = function() {
			responseContainer = arguments;
		};

		// Clean-up function (fires after converters)
		jqXHR.always( function() {

			// If previous value didn't exist - remove it
			if ( overwritten === undefined ) {
				jQuery( window ).removeProp( callbackName );

			// Otherwise restore preexisting value
			} else {
				window[ callbackName ] = overwritten;
			}

			// Save back as free
			if ( s[ callbackName ] ) {

				// Make sure that re-using the options doesn't screw things around
				s.jsonpCallback = originalSettings.jsonpCallback;

				// Save the callback name for future use
				oldCallbacks.push( callbackName );
			}

			// Call if it was a function and we have a response
			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
				overwritten( responseContainer[ 0 ] );
			}

			responseContainer = overwritten = undefined;
		} );

		// Delegate to script
		return "script";
	}
} );




// Argument "data" should be string of html
// context (optional): If specified, the fragment will be created in this context,
// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
	if ( !data || typeof data !== "string" ) {
		return null;
	}
	if ( typeof context === "boolean" ) {
		keepScripts = context;
		context = false;
	}
	context = context || document;

	var parsed = rsingleTag.exec( data ),
		scripts = !keepScripts && [];

	// Single tag
	if ( parsed ) {
		return [ context.createElement( parsed[ 1 ] ) ];
	}

	parsed = buildFragment( [ data ], context, scripts );

	if ( scripts && scripts.length ) {
		jQuery( scripts ).remove();
	}

	return jQuery.merge( [], parsed.childNodes );
};


// Keep a copy of the old load method
var _load = jQuery.fn.load;

/**
 * Load a url into a page
 */
jQuery.fn.load = function( url, params, callback ) {
	if ( typeof url !== "string" && _load ) {
		return _load.apply( this, arguments );
	}

	var selector, type, response,
		self = this,
		off = url.indexOf( " " );

	if ( off > -1 ) {
		selector = jQuery.trim( url.slice( off ) );
		url = url.slice( 0, off );
	}

	// If it's a function
	if ( jQuery.isFunction( params ) ) {

		// We assume that it's the callback
		callback = params;
		params = undefined;

	// Otherwise, build a param string
	} else if ( params && typeof params === "object" ) {
		type = "POST";
	}

	// If we have elements to modify, make the request
	if ( self.length > 0 ) {
		jQuery.ajax( {
			url: url,

			// If "type" variable is undefined, then "GET" method will be used.
			// Make value of this field explicit since
			// user can override it through ajaxSetup method
			type: type || "GET",
			dataType: "html",
			data: params
		} ).done( function( responseText ) {

			// Save response for use in complete callback
			response = arguments;

			self.html( selector ?

				// If a selector was specified, locate the right elements in a dummy div
				// Exclude scripts to avoid IE 'Permission Denied' errors
				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :

				// Otherwise use the full result
				responseText );

		// If the request succeeds, this function gets "data", "status", "jqXHR"
		// but they are ignored because response was set above.
		// If it fails, this function gets "jqXHR", "status", "error"
		} ).always( callback && function( jqXHR, status ) {
			self.each( function() {
				callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
			} );
		} );
	}

	return this;
};




// Attach a bunch of functions for handling common AJAX events
jQuery.each( [
	"ajaxStart",
	"ajaxStop",
	"ajaxComplete",
	"ajaxError",
	"ajaxSuccess",
	"ajaxSend"
], function( i, type ) {
	jQuery.fn[ type ] = function( fn ) {
		return this.on( type, fn );
	};
} );




jQuery.expr.filters.animated = function( elem ) {
	return jQuery.grep( jQuery.timers, function( fn ) {
		return elem === fn.elem;
	} ).length;
};




/**
 * Gets a window from an element
 */
function getWindow( elem ) {
	return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
}

jQuery.offset = {
	setOffset: function( elem, options, i ) {
		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
			position = jQuery.css( elem, "position" ),
			curElem = jQuery( elem ),
			props = {};

		// Set position first, in-case top/left are set even on static elem
		if ( position === "static" ) {
			elem.style.position = "relative";
		}

		curOffset = curElem.offset();
		curCSSTop = jQuery.css( elem, "top" );
		curCSSLeft = jQuery.css( elem, "left" );
		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
			( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;

		// Need to be able to calculate position if either
		// top or left is auto and position is either absolute or fixed
		if ( calculatePosition ) {
			curPosition = curElem.position();
			curTop = curPosition.top;
			curLeft = curPosition.left;

		} else {
			curTop = parseFloat( curCSSTop ) || 0;
			curLeft = parseFloat( curCSSLeft ) || 0;
		}

		if ( jQuery.isFunction( options ) ) {

			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
		}

		if ( options.top != null ) {
			props.top = ( options.top - curOffset.top ) + curTop;
		}
		if ( options.left != null ) {
			props.left = ( options.left - curOffset.left ) + curLeft;
		}

		if ( "using" in options ) {
			options.using.call( elem, props );

		} else {
			curElem.css( props );
		}
	}
};

jQuery.fn.extend( {
	offset: function( options ) {
		if ( arguments.length ) {
			return options === undefined ?
				this :
				this.each( function( i ) {
					jQuery.offset.setOffset( this, options, i );
				} );
		}

		var docElem, win,
			elem = this[ 0 ],
			box = { top: 0, left: 0 },
			doc = elem && elem.ownerDocument;

		if ( !doc ) {
			return;
		}

		docElem = doc.documentElement;

		// Make sure it's not a disconnected DOM node
		if ( !jQuery.contains( docElem, elem ) ) {
			return box;
		}

		box = elem.getBoundingClientRect();
		win = getWindow( doc );
		return {
			top: box.top + win.pageYOffset - docElem.clientTop,
			left: box.left + win.pageXOffset - docElem.clientLeft
		};
	},

	position: function() {
		if ( !this[ 0 ] ) {
			return;
		}

		var offsetParent, offset,
			elem = this[ 0 ],
			parentOffset = { top: 0, left: 0 };

		// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
		// because it is its only offset parent
		if ( jQuery.css( elem, "position" ) === "fixed" ) {

			// Assume getBoundingClientRect is there when computed position is fixed
			offset = elem.getBoundingClientRect();

		} else {

			// Get *real* offsetParent
			offsetParent = this.offsetParent();

			// Get correct offsets
			offset = this.offset();
			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
				parentOffset = offsetParent.offset();
			}

			// Add offsetParent borders
			parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
		}

		// Subtract parent offsets and element margins
		return {
			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
		};
	},

	// This method will return documentElement in the following cases:
	// 1) For the element inside the iframe without offsetParent, this method will return
	//    documentElement of the parent window
	// 2) For the hidden or detached element
	// 3) For body or html element, i.e. in case of the html node - it will return itself
	//
	// but those exceptions were never presented as a real life use-cases
	// and might be considered as more preferable results.
	//
	// This logic, however, is not guaranteed and can change at any point in the future
	offsetParent: function() {
		return this.map( function() {
			var offsetParent = this.offsetParent;

			while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
				offsetParent = offsetParent.offsetParent;
			}

			return offsetParent || documentElement;
		} );
	}
} );

// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
	var top = "pageYOffset" === prop;

	jQuery.fn[ method ] = function( val ) {
		return access( this, function( elem, method, val ) {
			var win = getWindow( elem );

			if ( val === undefined ) {
				return win ? win[ prop ] : elem[ method ];
			}

			if ( win ) {
				win.scrollTo(
					!top ? val : win.pageXOffset,
					top ? val : win.pageYOffset
				);

			} else {
				elem[ method ] = val;
			}
		}, method, val, arguments.length );
	};
} );

// Support: Safari<7-8+, Chrome<37-44+
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
// getComputedStyle returns percent when specified for top/left/bottom/right;
// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
		function( elem, computed ) {
			if ( computed ) {
				computed = curCSS( elem, prop );

				// If curCSS returns percentage, fallback to offset
				return rnumnonpx.test( computed ) ?
					jQuery( elem ).position()[ prop ] + "px" :
					computed;
			}
		}
	);
} );


// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
		function( defaultExtra, funcName ) {

		// Margin is only for outerHeight, outerWidth
		jQuery.fn[ funcName ] = function( margin, value ) {
			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );

			return access( this, function( elem, type, value ) {
				var doc;

				if ( jQuery.isWindow( elem ) ) {

					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
					// isn't a whole lot we can do. See pull request at this URL for discussion:
					// https://github.com/jquery/jquery/pull/764
					return elem.document.documentElement[ "client" + name ];
				}

				// Get document width or height
				if ( elem.nodeType === 9 ) {
					doc = elem.documentElement;

					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
					// whichever is greatest
					return Math.max(
						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
						elem.body[ "offset" + name ], doc[ "offset" + name ],
						doc[ "client" + name ]
					);
				}

				return value === undefined ?

					// Get width or height on the element, requesting but not forcing parseFloat
					jQuery.css( elem, type, extra ) :

					// Set width or height on the element
					jQuery.style( elem, type, value, extra );
			}, type, chainable ? margin : undefined, chainable, null );
		};
	} );
} );


jQuery.fn.extend( {

	bind: function( types, data, fn ) {
		return this.on( types, null, data, fn );
	},
	unbind: function( types, fn ) {
		return this.off( types, null, fn );
	},

	delegate: function( selector, types, data, fn ) {
		return this.on( types, selector, data, fn );
	},
	undelegate: function( selector, types, fn ) {

		// ( namespace ) or ( selector, types [, fn] )
		return arguments.length === 1 ?
			this.off( selector, "**" ) :
			this.off( types, selector || "**", fn );
	},
	size: function() {
		return this.length;
	}
} );

jQuery.fn.andSelf = jQuery.fn.addBack;




// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.

// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon

if ( typeof define === "function" && define.amd ) {
	define( "jquery", [], function() {
		return jQuery;
	} );
}



var

	// Map over jQuery in case of overwrite
	_jQuery = window.jQuery,

	// Map over the $ in case of overwrite
	_$ = window.$;

jQuery.noConflict = function( deep ) {
	if ( window.$ === jQuery ) {
		window.$ = _$;
	}

	if ( deep && window.jQuery === jQuery ) {
		window.jQuery = _jQuery;
	}

	return jQuery;
};

// Expose jQuery and $ identifiers, even in AMD
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( !noGlobal ) {
	window.jQuery = window.$ = jQuery;
}

return jQuery;
}));

},{}],215:[function(require,module,exports){
"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
var Cookie = {

  get: function get(name) {
    var match = document.cookie.match("(^|;) ?" + name + "=([^;]*)(;|$)");
    var value = match ? unescape(match[2]) : match;
    try {
      value = JSON.parse(value);
    } catch (e) {}
    return value;
  },

  set: function set(name, value) {
    var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];

    var cookie = name + "=" + escape(JSON.stringify(value)) + "; path=" + (options.path ? escape(options.path) : "/");
    if (options.domain) cookie += "; domain=" + escape(options.domain);
    if (options.secure) cookie += "; secure";
    if (options.expires) cookie += "; expires=" + options.expires;
    if (options.live) cookie += "; expires=" + expiresFromLive(options.live);
    document.cookie = cookie;
    return value;
  },

  remove: function remove(name) {
    var value = this.get(name);
    this.set(name, value, { live: -1 });
    return value;
  }

};

function expiresFromLive(live) {
  var date = new Date();
  date.setDate(date.getDate() + parseInt(live));
  date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
  return date.toUTCString();
}

exports["default"] = Cookie;
module.exports = exports["default"];

},{}],216:[function(require,module,exports){
(function (global){
/**
 * @license
 * Lodash <https://lodash.com/>
 * Copyright OpenJS Foundation and other contributors <https://openjsf.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
 */
;(function() {

  /** Used as a safe reference for `undefined` in pre-ES5 environments. */
  var undefined;

  /** Used as the semantic version number. */
  var VERSION = '4.17.21';

  /** Used as the size to enable large array optimizations. */
  var LARGE_ARRAY_SIZE = 200;

  /** Error message constants. */
  var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
      FUNC_ERROR_TEXT = 'Expected a function',
      INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`';

  /** Used to stand-in for `undefined` hash values. */
  var HASH_UNDEFINED = '__lodash_hash_undefined__';

  /** Used as the maximum memoize cache size. */
  var MAX_MEMOIZE_SIZE = 500;

  /** Used as the internal argument placeholder. */
  var PLACEHOLDER = '__lodash_placeholder__';

  /** Used to compose bitmasks for cloning. */
  var CLONE_DEEP_FLAG = 1,
      CLONE_FLAT_FLAG = 2,
      CLONE_SYMBOLS_FLAG = 4;

  /** Used to compose bitmasks for value comparisons. */
  var COMPARE_PARTIAL_FLAG = 1,
      COMPARE_UNORDERED_FLAG = 2;

  /** Used to compose bitmasks for function metadata. */
  var WRAP_BIND_FLAG = 1,
      WRAP_BIND_KEY_FLAG = 2,
      WRAP_CURRY_BOUND_FLAG = 4,
      WRAP_CURRY_FLAG = 8,
      WRAP_CURRY_RIGHT_FLAG = 16,
      WRAP_PARTIAL_FLAG = 32,
      WRAP_PARTIAL_RIGHT_FLAG = 64,
      WRAP_ARY_FLAG = 128,
      WRAP_REARG_FLAG = 256,
      WRAP_FLIP_FLAG = 512;

  /** Used as default options for `_.truncate`. */
  var DEFAULT_TRUNC_LENGTH = 30,
      DEFAULT_TRUNC_OMISSION = '...';

  /** Used to detect hot functions by number of calls within a span of milliseconds. */
  var HOT_COUNT = 800,
      HOT_SPAN = 16;

  /** Used to indicate the type of lazy iteratees. */
  var LAZY_FILTER_FLAG = 1,
      LAZY_MAP_FLAG = 2,
      LAZY_WHILE_FLAG = 3;

  /** Used as references for various `Number` constants. */
  var INFINITY = 1 / 0,
      MAX_SAFE_INTEGER = 9007199254740991,
      MAX_INTEGER = 1.7976931348623157e+308,
      NAN = 0 / 0;

  /** Used as references for the maximum length and index of an array. */
  var MAX_ARRAY_LENGTH = 4294967295,
      MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
      HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;

  /** Used to associate wrap methods with their bit flags. */
  var wrapFlags = [
    ['ary', WRAP_ARY_FLAG],
    ['bind', WRAP_BIND_FLAG],
    ['bindKey', WRAP_BIND_KEY_FLAG],
    ['curry', WRAP_CURRY_FLAG],
    ['curryRight', WRAP_CURRY_RIGHT_FLAG],
    ['flip', WRAP_FLIP_FLAG],
    ['partial', WRAP_PARTIAL_FLAG],
    ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
    ['rearg', WRAP_REARG_FLAG]
  ];

  /** `Object#toString` result references. */
  var argsTag = '[object Arguments]',
      arrayTag = '[object Array]',
      asyncTag = '[object AsyncFunction]',
      boolTag = '[object Boolean]',
      dateTag = '[object Date]',
      domExcTag = '[object DOMException]',
      errorTag = '[object Error]',
      funcTag = '[object Function]',
      genTag = '[object GeneratorFunction]',
      mapTag = '[object Map]',
      numberTag = '[object Number]',
      nullTag = '[object Null]',
      objectTag = '[object Object]',
      promiseTag = '[object Promise]',
      proxyTag = '[object Proxy]',
      regexpTag = '[object RegExp]',
      setTag = '[object Set]',
      stringTag = '[object String]',
      symbolTag = '[object Symbol]',
      undefinedTag = '[object Undefined]',
      weakMapTag = '[object WeakMap]',
      weakSetTag = '[object WeakSet]';

  var arrayBufferTag = '[object ArrayBuffer]',
      dataViewTag = '[object DataView]',
      float32Tag = '[object Float32Array]',
      float64Tag = '[object Float64Array]',
      int8Tag = '[object Int8Array]',
      int16Tag = '[object Int16Array]',
      int32Tag = '[object Int32Array]',
      uint8Tag = '[object Uint8Array]',
      uint8ClampedTag = '[object Uint8ClampedArray]',
      uint16Tag = '[object Uint16Array]',
      uint32Tag = '[object Uint32Array]';

  /** Used to match empty string literals in compiled template source. */
  var reEmptyStringLeading = /\b__p \+= '';/g,
      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;

  /** Used to match HTML entities and HTML characters. */
  var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
      reUnescapedHtml = /[&<>"']/g,
      reHasEscapedHtml = RegExp(reEscapedHtml.source),
      reHasUnescapedHtml = RegExp(reUnescapedHtml.source);

  /** Used to match template delimiters. */
  var reEscape = /<%-([\s\S]+?)%>/g,
      reEvaluate = /<%([\s\S]+?)%>/g,
      reInterpolate = /<%=([\s\S]+?)%>/g;

  /** Used to match property names within property paths. */
  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
      reIsPlainProp = /^\w*$/,
      rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;

  /**
   * Used to match `RegExp`
   * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
   */
  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
      reHasRegExpChar = RegExp(reRegExpChar.source);

  /** Used to match leading whitespace. */
  var reTrimStart = /^\s+/;

  /** Used to match a single whitespace character. */
  var reWhitespace = /\s/;

  /** Used to match wrap detail comments. */
  var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
      reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
      reSplitDetails = /,? & /;

  /** Used to match words composed of alphanumeric characters. */
  var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;

  /**
   * Used to validate the `validate` option in `_.template` variable.
   *
   * Forbids characters which could potentially change the meaning of the function argument definition:
   * - "()," (modification of function parameters)
   * - "=" (default value)
   * - "[]{}" (destructuring of function parameters)
   * - "/" (beginning of a comment)
   * - whitespace
   */
  var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/;

  /** Used to match backslashes in property paths. */
  var reEscapeChar = /\\(\\)?/g;

  /**
   * Used to match
   * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
   */
  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;

  /** Used to match `RegExp` flags from their coerced string values. */
  var reFlags = /\w*$/;

  /** Used to detect bad signed hexadecimal string values. */
  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;

  /** Used to detect binary string values. */
  var reIsBinary = /^0b[01]+$/i;

  /** Used to detect host constructors (Safari). */
  var reIsHostCtor = /^\[object .+?Constructor\]$/;

  /** Used to detect octal string values. */
  var reIsOctal = /^0o[0-7]+$/i;

  /** Used to detect unsigned integer values. */
  var reIsUint = /^(?:0|[1-9]\d*)$/;

  /** Used to match Latin Unicode letters (excluding mathematical operators). */
  var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;

  /** Used to ensure capturing order of template delimiters. */
  var reNoMatch = /($^)/;

  /** Used to match unescaped characters in compiled string literals. */
  var reUnescapedString = /['\n\r\u2028\u2029\\]/g;

  /** Used to compose unicode character classes. */
  var rsAstralRange = '\\ud800-\\udfff',
      rsComboMarksRange = '\\u0300-\\u036f',
      reComboHalfMarksRange = '\\ufe20-\\ufe2f',
      rsComboSymbolsRange = '\\u20d0-\\u20ff',
      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
      rsDingbatRange = '\\u2700-\\u27bf',
      rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
      rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
      rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
      rsPunctuationRange = '\\u2000-\\u206f',
      rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
      rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
      rsVarRange = '\\ufe0e\\ufe0f',
      rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;

  /** Used to compose unicode capture groups. */
  var rsApos = "['\u2019]",
      rsAstral = '[' + rsAstralRange + ']',
      rsBreak = '[' + rsBreakRange + ']',
      rsCombo = '[' + rsComboRange + ']',
      rsDigits = '\\d+',
      rsDingbat = '[' + rsDingbatRange + ']',
      rsLower = '[' + rsLowerRange + ']',
      rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
      rsFitz = '\\ud83c[\\udffb-\\udfff]',
      rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
      rsNonAstral = '[^' + rsAstralRange + ']',
      rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
      rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
      rsUpper = '[' + rsUpperRange + ']',
      rsZWJ = '\\u200d';

  /** Used to compose unicode regexes. */
  var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
      rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
      rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
      rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
      reOptMod = rsModifier + '?',
      rsOptVar = '[' + rsVarRange + ']?',
      rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
      rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
      rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
      rsSeq = rsOptVar + reOptMod + rsOptJoin,
      rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
      rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';

  /** Used to match apostrophes. */
  var reApos = RegExp(rsApos, 'g');

  /**
   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
   */
  var reComboMark = RegExp(rsCombo, 'g');

  /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
  var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');

  /** Used to match complex or compound words. */
  var reUnicodeWord = RegExp([
    rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
    rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
    rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
    rsUpper + '+' + rsOptContrUpper,
    rsOrdUpper,
    rsOrdLower,
    rsDigits,
    rsEmoji
  ].join('|'), '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  + rsComboRange + rsVarRange + ']');

  /** Used to detect strings that need a more robust regexp to match words. */
  var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;

  /** Used to assign default `context` object properties. */
  var contextProps = [
    'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
    'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
    'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
    'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
    '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
  ];

  /** Used to make template sourceURLs easier to identify. */
  var templateCounter = -1;

  /** Used to identify `toStringTag` values of typed arrays. */
  var typedArrayTags = {};
  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
  typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
  typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
  typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
  typedArrayTags[uint32Tag] = true;
  typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
  typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
  typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
  typedArrayTags[errorTag] = typedArrayTags[funcTag] =
  typedArrayTags[mapTag] = typedArrayTags[numberTag] =
  typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
  typedArrayTags[setTag] = typedArrayTags[stringTag] =
  typedArrayTags[weakMapTag] = false;

  /** Used to identify `toStringTag` values supported by `_.clone`. */
  var cloneableTags = {};
  cloneableTags[argsTag] = cloneableTags[arrayTag] =
  cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
  cloneableTags[boolTag] = cloneableTags[dateTag] =
  cloneableTags[float32Tag] = cloneableTags[float64Tag] =
  cloneableTags[int8Tag] = cloneableTags[int16Tag] =
  cloneableTags[int32Tag] = cloneableTags[mapTag] =
  cloneableTags[numberTag] = cloneableTags[objectTag] =
  cloneableTags[regexpTag] = cloneableTags[setTag] =
  cloneableTags[stringTag] = cloneableTags[symbolTag] =
  cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
  cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
  cloneableTags[errorTag] = cloneableTags[funcTag] =
  cloneableTags[weakMapTag] = false;

  /** Used to map Latin Unicode letters to basic Latin letters. */
  var deburredLetters = {
    // Latin-1 Supplement block.
    '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
    '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
    '\xc7': 'C',  '\xe7': 'c',
    '\xd0': 'D',  '\xf0': 'd',
    '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
    '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
    '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
    '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
    '\xd1': 'N',  '\xf1': 'n',
    '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
    '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
    '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
    '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
    '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
    '\xc6': 'Ae', '\xe6': 'ae',
    '\xde': 'Th', '\xfe': 'th',
    '\xdf': 'ss',
    // Latin Extended-A block.
    '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
    '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
    '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
    '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
    '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
    '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
    '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
    '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
    '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
    '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
    '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
    '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
    '\u0134': 'J',  '\u0135': 'j',
    '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
    '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
    '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
    '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
    '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
    '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
    '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
    '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
    '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
    '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
    '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
    '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
    '\u0163': 't',  '\u0165': 't', '\u0167': 't',
    '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
    '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
    '\u0174': 'W',  '\u0175': 'w',
    '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
    '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
    '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
    '\u0132': 'IJ', '\u0133': 'ij',
    '\u0152': 'Oe', '\u0153': 'oe',
    '\u0149': "'n", '\u017f': 's'
  };

  /** Used to map characters to HTML entities. */
  var htmlEscapes = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;'
  };

  /** Used to map HTML entities to characters. */
  var htmlUnescapes = {
    '&amp;': '&',
    '&lt;': '<',
    '&gt;': '>',
    '&quot;': '"',
    '&#39;': "'"
  };

  /** Used to escape characters for inclusion in compiled string literals. */
  var stringEscapes = {
    '\\': '\\',
    "'": "'",
    '\n': 'n',
    '\r': 'r',
    '\u2028': 'u2028',
    '\u2029': 'u2029'
  };

  /** Built-in method references without a dependency on `root`. */
  var freeParseFloat = parseFloat,
      freeParseInt = parseInt;

  /** Detect free variable `global` from Node.js. */
  var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;

  /** 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')();

  /** Detect free variable `exports`. */
  var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;

  /** Detect free variable `module`. */
  var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;

  /** Detect the popular CommonJS extension `module.exports`. */
  var moduleExports = freeModule && freeModule.exports === freeExports;

  /** Detect free variable `process` from Node.js. */
  var freeProcess = moduleExports && freeGlobal.process;

  /** Used to access faster Node.js helpers. */
  var nodeUtil = (function() {
    try {
      // Use `util.types` for Node.js 10+.
      var types = freeModule && freeModule.require && freeModule.require('util').types;

      if (types) {
        return types;
      }

      // Legacy `process.binding('util')` for Node.js < 10.
      return freeProcess && freeProcess.binding && freeProcess.binding('util');
    } catch (e) {}
  }());

  /* Node.js helper references. */
  var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
      nodeIsDate = nodeUtil && nodeUtil.isDate,
      nodeIsMap = nodeUtil && nodeUtil.isMap,
      nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
      nodeIsSet = nodeUtil && nodeUtil.isSet,
      nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;

  /*--------------------------------------------------------------------------*/

  /**
   * A faster alternative to `Function#apply`, this function invokes `func`
   * with the `this` binding of `thisArg` and the arguments of `args`.
   *
   * @private
   * @param {Function} func The function to invoke.
   * @param {*} thisArg The `this` binding of `func`.
   * @param {Array} args The arguments to invoke `func` with.
   * @returns {*} Returns the result of `func`.
   */
  function apply(func, thisArg, args) {
    switch (args.length) {
      case 0: return func.call(thisArg);
      case 1: return func.call(thisArg, args[0]);
      case 2: return func.call(thisArg, args[0], args[1]);
      case 3: return func.call(thisArg, args[0], args[1], args[2]);
    }
    return func.apply(thisArg, args);
  }

  /**
   * A specialized version of `baseAggregator` for arrays.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} setter The function to set `accumulator` values.
   * @param {Function} iteratee The iteratee to transform keys.
   * @param {Object} accumulator The initial aggregated object.
   * @returns {Function} Returns `accumulator`.
   */
  function arrayAggregator(array, setter, iteratee, accumulator) {
    var index = -1,
        length = array == null ? 0 : array.length;

    while (++index < length) {
      var value = array[index];
      setter(accumulator, value, iteratee(value), array);
    }
    return accumulator;
  }

  /**
   * A specialized version of `_.forEach` 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 `array`.
   */
  function arrayEach(array, iteratee) {
    var index = -1,
        length = array == null ? 0 : array.length;

    while (++index < length) {
      if (iteratee(array[index], index, array) === false) {
        break;
      }
    }
    return array;
  }

  /**
   * A specialized version of `_.forEachRight` 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 `array`.
   */
  function arrayEachRight(array, iteratee) {
    var length = array == null ? 0 : array.length;

    while (length--) {
      if (iteratee(array[length], length, array) === false) {
        break;
      }
    }
    return array;
  }

  /**
   * A specialized version of `_.every` for arrays without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} predicate The function invoked per iteration.
   * @returns {boolean} Returns `true` if all elements pass the predicate check,
   *  else `false`.
   */
  function arrayEvery(array, predicate) {
    var index = -1,
        length = array == null ? 0 : array.length;

    while (++index < length) {
      if (!predicate(array[index], index, array)) {
        return false;
      }
    }
    return true;
  }

  /**
   * A specialized version of `_.filter` for arrays without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} predicate The function invoked per iteration.
   * @returns {Array} Returns the new filtered array.
   */
  function arrayFilter(array, predicate) {
    var index = -1,
        length = array == null ? 0 : array.length,
        resIndex = 0,
        result = [];

    while (++index < length) {
      var value = array[index];
      if (predicate(value, index, array)) {
        result[resIndex++] = value;
      }
    }
    return result;
  }

  /**
   * A specialized version of `_.includes` for arrays without support for
   * specifying an index to search from.
   *
   * @private
   * @param {Array} [array] The array to inspect.
   * @param {*} target The value to search for.
   * @returns {boolean} Returns `true` if `target` is found, else `false`.
   */
  function arrayIncludes(array, value) {
    var length = array == null ? 0 : array.length;
    return !!length && baseIndexOf(array, value, 0) > -1;
  }

  /**
   * This function is like `arrayIncludes` except that it accepts a comparator.
   *
   * @private
   * @param {Array} [array] The array to inspect.
   * @param {*} target The value to search for.
   * @param {Function} comparator The comparator invoked per element.
   * @returns {boolean} Returns `true` if `target` is found, else `false`.
   */
  function arrayIncludesWith(array, value, comparator) {
    var index = -1,
        length = array == null ? 0 : array.length;

    while (++index < length) {
      if (comparator(value, array[index])) {
        return true;
      }
    }
    return false;
  }

  /**
   * 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 == null ? 0 : array.length,
        result = Array(length);

    while (++index < length) {
      result[index] = iteratee(array[index], index, array);
    }
    return result;
  }

  /**
   * Appends the elements of `values` to `array`.
   *
   * @private
   * @param {Array} array The array to modify.
   * @param {Array} values The values to append.
   * @returns {Array} Returns `array`.
   */
  function arrayPush(array, values) {
    var index = -1,
        length = values.length,
        offset = array.length;

    while (++index < length) {
      array[offset + index] = values[index];
    }
    return array;
  }

  /**
   * A specialized version of `_.reduce` for arrays without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {*} [accumulator] The initial value.
   * @param {boolean} [initAccum] Specify using the first element of `array` as
   *  the initial value.
   * @returns {*} Returns the accumulated value.
   */
  function arrayReduce(array, iteratee, accumulator, initAccum) {
    var index = -1,
        length = array == null ? 0 : array.length;

    if (initAccum && length) {
      accumulator = array[++index];
    }
    while (++index < length) {
      accumulator = iteratee(accumulator, array[index], index, array);
    }
    return accumulator;
  }

  /**
   * A specialized version of `_.reduceRight` for arrays without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {*} [accumulator] The initial value.
   * @param {boolean} [initAccum] Specify using the last element of `array` as
   *  the initial value.
   * @returns {*} Returns the accumulated value.
   */
  function arrayReduceRight(array, iteratee, accumulator, initAccum) {
    var length = array == null ? 0 : array.length;
    if (initAccum && length) {
      accumulator = array[--length];
    }
    while (length--) {
      accumulator = iteratee(accumulator, array[length], length, array);
    }
    return accumulator;
  }

  /**
   * A specialized version of `_.some` for arrays without support for iteratee
   * shorthands.
   *
   * @private
   * @param {Array} [array] The array to iterate over.
   * @param {Function} predicate The function invoked per iteration.
   * @returns {boolean} Returns `true` if any element passes the predicate check,
   *  else `false`.
   */
  function arraySome(array, predicate) {
    var index = -1,
        length = array == null ? 0 : array.length;

    while (++index < length) {
      if (predicate(array[index], index, array)) {
        return true;
      }
    }
    return false;
  }

  /**
   * Gets the size of an ASCII `string`.
   *
   * @private
   * @param {string} string The string inspect.
   * @returns {number} Returns the string size.
   */
  var asciiSize = baseProperty('length');

  /**
   * 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('');
  }

  /**
   * Splits an ASCII `string` into an array of its words.
   *
   * @private
   * @param {string} The string to inspect.
   * @returns {Array} Returns the words of `string`.
   */
  function asciiWords(string) {
    return string.match(reAsciiWord) || [];
  }

  /**
   * The base implementation of methods like `_.findKey` and `_.findLastKey`,
   * without support for iteratee shorthands, which iterates over `collection`
   * using `eachFunc`.
   *
   * @private
   * @param {Array|Object} collection The collection to inspect.
   * @param {Function} predicate The function invoked per iteration.
   * @param {Function} eachFunc The function to iterate over `collection`.
   * @returns {*} Returns the found element or its key, else `undefined`.
   */
  function baseFindKey(collection, predicate, eachFunc) {
    var result;
    eachFunc(collection, function(value, key, collection) {
      if (predicate(value, key, collection)) {
        result = key;
        return false;
      }
    });
    return result;
  }

  /**
   * The base implementation of `_.findIndex` and `_.findLastIndex` without
   * support for iteratee shorthands.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {Function} predicate The function invoked per iteration.
   * @param {number} fromIndex The index to search from.
   * @param {boolean} [fromRight] Specify iterating from right to left.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function baseFindIndex(array, predicate, fromIndex, fromRight) {
    var length = array.length,
        index = fromIndex + (fromRight ? 1 : -1);

    while ((fromRight ? index-- : ++index < length)) {
      if (predicate(array[index], index, array)) {
        return index;
      }
    }
    return -1;
  }

  /**
   * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} value The value to search for.
   * @param {number} fromIndex The index to search from.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function baseIndexOf(array, value, fromIndex) {
    return value === value
      ? strictIndexOf(array, value, fromIndex)
      : baseFindIndex(array, baseIsNaN, fromIndex);
  }

  /**
   * This function is like `baseIndexOf` except that it accepts a comparator.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} value The value to search for.
   * @param {number} fromIndex The index to search from.
   * @param {Function} comparator The comparator invoked per element.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function baseIndexOfWith(array, value, fromIndex, comparator) {
    var index = fromIndex - 1,
        length = array.length;

    while (++index < length) {
      if (comparator(array[index], value)) {
        return index;
      }
    }
    return -1;
  }

  /**
   * The base implementation of `_.isNaN` without support for number objects.
   *
   * @private
   * @param {*} value The value to check.
   * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
   */
  function baseIsNaN(value) {
    return value !== value;
  }

  /**
   * The base implementation of `_.mean` and `_.meanBy` without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} array The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @returns {number} Returns the mean.
   */
  function baseMean(array, iteratee) {
    var length = array == null ? 0 : array.length;
    return length ? (baseSum(array, iteratee) / length) : NAN;
  }

  /**
   * The base implementation of `_.property` without support for deep paths.
   *
   * @private
   * @param {string} key The key of the property to get.
   * @returns {Function} Returns the new accessor function.
   */
  function baseProperty(key) {
    return function(object) {
      return object == null ? undefined : object[key];
    };
  }

  /**
   * The base implementation of `_.propertyOf` without support for deep paths.
   *
   * @private
   * @param {Object} object The object to query.
   * @returns {Function} Returns the new accessor function.
   */
  function basePropertyOf(object) {
    return function(key) {
      return object == null ? undefined : object[key];
    };
  }

  /**
   * The base implementation of `_.reduce` and `_.reduceRight`, without support
   * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
   *
   * @private
   * @param {Array|Object} collection The collection to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @param {*} accumulator The initial value.
   * @param {boolean} initAccum Specify using the first or last element of
   *  `collection` as the initial value.
   * @param {Function} eachFunc The function to iterate over `collection`.
   * @returns {*} Returns the accumulated value.
   */
  function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
    eachFunc(collection, function(value, index, collection) {
      accumulator = initAccum
        ? (initAccum = false, value)
        : iteratee(accumulator, value, index, collection);
    });
    return accumulator;
  }

  /**
   * The base implementation of `_.sortBy` which uses `comparer` to define the
   * sort order of `array` and replaces criteria objects with their corresponding
   * values.
   *
   * @private
   * @param {Array} array The array to sort.
   * @param {Function} comparer The function to define sort order.
   * @returns {Array} Returns `array`.
   */
  function baseSortBy(array, comparer) {
    var length = array.length;

    array.sort(comparer);
    while (length--) {
      array[length] = array[length].value;
    }
    return array;
  }

  /**
   * The base implementation of `_.sum` and `_.sumBy` without support for
   * iteratee shorthands.
   *
   * @private
   * @param {Array} array The array to iterate over.
   * @param {Function} iteratee The function invoked per iteration.
   * @returns {number} Returns the sum.
   */
  function baseSum(array, iteratee) {
    var result,
        index = -1,
        length = array.length;

    while (++index < length) {
      var current = iteratee(array[index]);
      if (current !== undefined) {
        result = result === undefined ? current : (result + current);
      }
    }
    return result;
  }

  /**
   * 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 `_.toPairs` and `_.toPairsIn` which creates an array
   * of key-value pairs for `object` 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 key-value pairs.
   */
  function baseToPairs(object, props) {
    return arrayMap(props, function(key) {
      return [key, object[key]];
    });
  }

  /**
   * The base implementation of `_.trim`.
   *
   * @private
   * @param {string} string The string to trim.
   * @returns {string} Returns the trimmed string.
   */
  function baseTrim(string) {
    return string
      ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
      : string;
  }

  /**
   * The base implementation of `_.unary` without support for storing metadata.
   *
   * @private
   * @param {Function} func The function to cap arguments for.
   * @returns {Function} Returns the new capped function.
   */
  function baseUnary(func) {
    return function(value) {
      return func(value);
    };
  }

  /**
   * 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];
    });
  }

  /**
   * Checks if a `cache` value for `key` exists.
   *
   * @private
   * @param {Object} cache The cache to query.
   * @param {string} key The key of the entry to check.
   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
   */
  function cacheHas(cache, key) {
    return cache.has(key);
  }

  /**
   * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
   * that is not found in the character symbols.
   *
   * @private
   * @param {Array} strSymbols The string symbols to inspect.
   * @param {Array} chrSymbols The character symbols to find.
   * @returns {number} Returns the index of the first unmatched string symbol.
   */
  function charsStartIndex(strSymbols, chrSymbols) {
    var index = -1,
        length = strSymbols.length;

    while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
    return index;
  }

  /**
   * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
   * that is not found in the character symbols.
   *
   * @private
   * @param {Array} strSymbols The string symbols to inspect.
   * @param {Array} chrSymbols The character symbols to find.
   * @returns {number} Returns the index of the last unmatched string symbol.
   */
  function charsEndIndex(strSymbols, chrSymbols) {
    var index = strSymbols.length;

    while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
    return index;
  }

  /**
   * Gets the number of `placeholder` occurrences in `array`.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} placeholder The placeholder to search for.
   * @returns {number} Returns the placeholder count.
   */
  function countHolders(array, placeholder) {
    var length = array.length,
        result = 0;

    while (length--) {
      if (array[length] === placeholder) {
        ++result;
      }
    }
    return result;
  }

  /**
   * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
   * letters to basic Latin letters.
   *
   * @private
   * @param {string} letter The matched letter to deburr.
   * @returns {string} Returns the deburred letter.
   */
  var deburrLetter = basePropertyOf(deburredLetters);

  /**
   * Used by `_.escape` to convert characters to HTML entities.
   *
   * @private
   * @param {string} chr The matched character to escape.
   * @returns {string} Returns the escaped character.
   */
  var escapeHtmlChar = basePropertyOf(htmlEscapes);

  /**
   * Used by `_.template` to escape characters for inclusion in compiled string literals.
   *
   * @private
   * @param {string} chr The matched character to escape.
   * @returns {string} Returns the escaped character.
   */
  function escapeStringChar(chr) {
    return '\\' + stringEscapes[chr];
  }

  /**
   * 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 `string` contains a word composed of Unicode symbols.
   *
   * @private
   * @param {string} string The string to inspect.
   * @returns {boolean} Returns `true` if a word is found, else `false`.
   */
  function hasUnicodeWord(string) {
    return reHasUnicodeWord.test(string);
  }

  /**
   * 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));
    };
  }

  /**
   * Replaces all `placeholder` elements in `array` with an internal placeholder
   * and returns an array of their indexes.
   *
   * @private
   * @param {Array} array The array to modify.
   * @param {*} placeholder The placeholder to replace.
   * @returns {Array} Returns the new array of placeholder indexes.
   */
  function replaceHolders(array, placeholder) {
    var index = -1,
        length = array.length,
        resIndex = 0,
        result = [];

    while (++index < length) {
      var value = array[index];
      if (value === placeholder || value === PLACEHOLDER) {
        array[index] = PLACEHOLDER;
        result[resIndex++] = index;
      }
    }
    return result;
  }

  /**
   * 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 `set` to its value-value pairs.
   *
   * @private
   * @param {Object} set The set to convert.
   * @returns {Array} Returns the value-value pairs.
   */
  function setToPairs(set) {
    var index = -1,
        result = Array(set.size);

    set.forEach(function(value) {
      result[++index] = [value, value];
    });
    return result;
  }

  /**
   * A specialized version of `_.indexOf` which performs strict equality
   * comparisons of values, i.e. `===`.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} value The value to search for.
   * @param {number} fromIndex The index to search from.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function strictIndexOf(array, value, fromIndex) {
    var index = fromIndex - 1,
        length = array.length;

    while (++index < length) {
      if (array[index] === value) {
        return index;
      }
    }
    return -1;
  }

  /**
   * A specialized version of `_.lastIndexOf` which performs strict equality
   * comparisons of values, i.e. `===`.
   *
   * @private
   * @param {Array} array The array to inspect.
   * @param {*} value The value to search for.
   * @param {number} fromIndex The index to search from.
   * @returns {number} Returns the index of the matched value, else `-1`.
   */
  function strictLastIndexOf(array, value, fromIndex) {
    var index = fromIndex + 1;
    while (index--) {
      if (array[index] === value) {
        return index;
      }
    }
    return index;
  }

  /**
   * Gets the number of symbols in `string`.
   *
   * @private
   * @param {string} string The string to inspect.
   * @returns {number} Returns the string size.
   */
  function stringSize(string) {
    return hasUnicode(string)
      ? unicodeSize(string)
      : asciiSize(string);
  }

  /**
   * 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);
  }

  /**
   * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
   * character of `string`.
   *
   * @private
   * @param {string} string The string to inspect.
   * @returns {number} Returns the index of the last non-whitespace character.
   */
  function trimmedEndIndex(string) {
    var index = string.length;

    while (index-- && reWhitespace.test(string.charAt(index))) {}
    return index;
  }

  /**
   * Used by `_.unescape` to convert HTML entities to characters.
   *
   * @private
   * @param {string} chr The matched character to unescape.
   * @returns {string} Returns the unescaped character.
   */
  var unescapeHtmlChar = basePropertyOf(htmlUnescapes);

  /**
   * Gets the size of a Unicode `string`.
   *
   * @private
   * @param {string} string The string inspect.
   * @returns {number} Returns the string size.
   */
  function unicodeSize(string) {
    var result = reUnicode.lastIndex = 0;
    while (reUnicode.test(string)) {
      ++result;
    }
    return result;
  }

  /**
   * 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) || [];
  }

  /**
   * Splits a Unicode `string` into an array of its words.
   *
   * @private
   * @param {string} The string to inspect.
   * @returns {Array} Returns the words of `string`.
   */
  function unicodeWords(string) {
    return string.match(reUnicodeWord) || [];
  }

  /*--------------------------------------------------------------------------*/

  /**
   * Create a new pristine `lodash` function using the `context` object.
   *
   * @static
   * @memberOf _
   * @since 1.1.0
   * @category Util
   * @param {Object} [context=root] The context object.
   * @returns {Function} Returns a new `lodash` function.
   * @example
   *
   * _.mixin({ 'foo': _.constant('foo') });
   *
   * var lodash = _.runInContext();
   * lodash.mixin({ 'bar': lodash.constant('bar') });
   *
   * _.isFunction(_.foo);
   * // => true
   * _.isFunction(_.bar);
   * // => false
   *
   * lodash.isFunction(lodash.foo);
   * // => false
   * lodash.isFunction(lodash.bar);
   * // => true
   *
   * // Create a suped-up `defer` in Node.js.
   * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
   */
  var runInContext = (function runInContext(context) {
    context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));

    /** Built-in constructor references. */
    var Array = context.Array,
        Date = context.Date,
        Error = context.Error,
        Function = context.Function,
        Math = context.Math,
        Object = context.Object,
        RegExp = context.RegExp,
        String = context.String,
        TypeError = context.TypeError;

    /** Used for built-in method references. */
    var arrayProto = Array.prototype,
        funcProto = Function.prototype,
        objectProto = Object.prototype;

    /** Used to detect overreaching core-js shims. */
    var coreJsData = context['__core-js_shared__'];

    /** 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 generate unique IDs. */
    var idCounter = 0;

    /** 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
     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
     * of values.
     */
    var nativeObjectToString = objectProto.toString;

    /** Used to infer the `Object` constructor. */
    var objectCtorString = funcToString.call(Object);

    /** Used to restore the original `_` reference in `_.noConflict`. */
    var oldDash = root._;

    /** 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 Buffer = moduleExports ? context.Buffer : undefined,
        Symbol = context.Symbol,
        Uint8Array = context.Uint8Array,
        allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
        getPrototype = overArg(Object.getPrototypeOf, Object),
        objectCreate = Object.create,
        propertyIsEnumerable = objectProto.propertyIsEnumerable,
        splice = arrayProto.splice,
        spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
        symIterator = Symbol ? Symbol.iterator : undefined,
        symToStringTag = Symbol ? Symbol.toStringTag : undefined;

    var defineProperty = (function() {
      try {
        var func = getNative(Object, 'defineProperty');
        func({}, '', {});
        return func;
      } catch (e) {}
    }());

    /** Mocked built-ins. */
    var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
        ctxNow = Date && Date.now !== root.Date.now && Date.now,
        ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;

    /* Built-in method references for those with the same name as other `lodash` methods. */
    var nativeCeil = Math.ceil,
        nativeFloor = Math.floor,
        nativeGetSymbols = Object.getOwnPropertySymbols,
        nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
        nativeIsFinite = context.isFinite,
        nativeJoin = arrayProto.join,
        nativeKeys = overArg(Object.keys, Object),
        nativeMax = Math.max,
        nativeMin = Math.min,
        nativeNow = Date.now,
        nativeParseInt = context.parseInt,
        nativeRandom = Math.random,
        nativeReverse = arrayProto.reverse;

    /* Built-in method references that are verified to be native. */
    var DataView = getNative(context, 'DataView'),
        Map = getNative(context, 'Map'),
        Promise = getNative(context, 'Promise'),
        Set = getNative(context, 'Set'),
        WeakMap = getNative(context, 'WeakMap'),
        nativeCreate = getNative(Object, 'create');

    /** Used to store function metadata. */
    var metaMap = WeakMap && new WeakMap;

    /** Used to lookup unminified function names. */
    var realNames = {};

    /** Used to detect maps, sets, and weakmaps. */
    var dataViewCtorString = toSource(DataView),
        mapCtorString = toSource(Map),
        promiseCtorString = toSource(Promise),
        setCtorString = toSource(Set),
        weakMapCtorString = toSource(WeakMap);

    /** Used to convert symbols to primitives and strings. */
    var symbolProto = Symbol ? Symbol.prototype : undefined,
        symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
        symbolToString = symbolProto ? symbolProto.toString : undefined;

    /*------------------------------------------------------------------------*/

    /**
     * Creates a `lodash` object which wraps `value` to enable implicit method
     * chain sequences. Methods that operate on and return arrays, collections,
     * and functions can be chained together. Methods that retrieve a single value
     * or may return a primitive value will automatically end the chain sequence
     * and return the unwrapped value. Otherwise, the value must be unwrapped
     * with `_#value`.
     *
     * Explicit chain sequences, which must be unwrapped with `_#value`, may be
     * enabled using `_.chain`.
     *
     * The execution of chained methods is lazy, that is, it's deferred until
     * `_#value` is implicitly or explicitly called.
     *
     * Lazy evaluation allows several methods to support shortcut fusion.
     * Shortcut fusion is an optimization to merge iteratee calls; this avoids
     * the creation of intermediate arrays and can greatly reduce the number of
     * iteratee executions. Sections of a chain sequence qualify for shortcut
     * fusion if the section is applied to an array and iteratees accept only
     * one argument. The heuristic for whether a section qualifies for shortcut
     * fusion is subject to change.
     *
     * Chaining is supported in custom builds as long as the `_#value` method is
     * directly or indirectly included in the build.
     *
     * In addition to lodash methods, wrappers have `Array` and `String` methods.
     *
     * The wrapper `Array` methods are:
     * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
     *
     * The wrapper `String` methods are:
     * `replace` and `split`
     *
     * The wrapper methods that support shortcut fusion are:
     * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
     * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
     * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
     *
     * The chainable wrapper methods are:
     * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
     * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
     * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
     * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
     * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
     * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
     * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
     * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
     * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
     * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
     * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
     * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
     * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
     * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
     * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
     * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
     * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
     * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
     * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
     * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
     * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
     * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
     * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
     * `zipObject`, `zipObjectDeep`, and `zipWith`
     *
     * The wrapper methods that are **not** chainable by default are:
     * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
     * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
     * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
     * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
     * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
     * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
     * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
     * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
     * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
     * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
     * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
     * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
     * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
     * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
     * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
     * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
     * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
     * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
     * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
     * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
     * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
     * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
     * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
     * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
     * `upperFirst`, `value`, and `words`
     *
     * @name _
     * @constructor
     * @category Seq
     * @param {*} value The value to wrap in a `lodash` instance.
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * var wrapped = _([1, 2, 3]);
     *
     * // Returns an unwrapped value.
     * wrapped.reduce(_.add);
     * // => 6
     *
     * // Returns a wrapped value.
     * var squares = wrapped.map(square);
     *
     * _.isArray(squares);
     * // => false
     *
     * _.isArray(squares.value());
     * // => true
     */
    function lodash(value) {
      if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
        if (value instanceof LodashWrapper) {
          return value;
        }
        if (hasOwnProperty.call(value, '__wrapped__')) {
          return wrapperClone(value);
        }
      }
      return new LodashWrapper(value);
    }

    /**
     * The base implementation of `_.create` without support for assigning
     * properties to the created object.
     *
     * @private
     * @param {Object} proto The object to inherit from.
     * @returns {Object} Returns the new object.
     */
    var baseCreate = (function() {
      function object() {}
      return function(proto) {
        if (!isObject(proto)) {
          return {};
        }
        if (objectCreate) {
          return objectCreate(proto);
        }
        object.prototype = proto;
        var result = new object;
        object.prototype = undefined;
        return result;
      };
    }());

    /**
     * The function whose prototype chain sequence wrappers inherit from.
     *
     * @private
     */
    function baseLodash() {
      // No operation performed.
    }

    /**
     * The base constructor for creating `lodash` wrapper objects.
     *
     * @private
     * @param {*} value The value to wrap.
     * @param {boolean} [chainAll] Enable explicit method chain sequences.
     */
    function LodashWrapper(value, chainAll) {
      this.__wrapped__ = value;
      this.__actions__ = [];
      this.__chain__ = !!chainAll;
      this.__index__ = 0;
      this.__values__ = undefined;
    }

    /**
     * By default, the template delimiters used by lodash are like those in
     * embedded Ruby (ERB) as well as ES2015 template strings. Change the
     * following template settings to use alternative delimiters.
     *
     * @static
     * @memberOf _
     * @type {Object}
     */
    lodash.templateSettings = {

      /**
       * Used to detect `data` property values to be HTML-escaped.
       *
       * @memberOf _.templateSettings
       * @type {RegExp}
       */
      'escape': reEscape,

      /**
       * Used to detect code to be evaluated.
       *
       * @memberOf _.templateSettings
       * @type {RegExp}
       */
      'evaluate': reEvaluate,

      /**
       * Used to detect `data` property values to inject.
       *
       * @memberOf _.templateSettings
       * @type {RegExp}
       */
      'interpolate': reInterpolate,

      /**
       * Used to reference the data object in the template text.
       *
       * @memberOf _.templateSettings
       * @type {string}
       */
      'variable': '',

      /**
       * Used to import variables into the compiled template.
       *
       * @memberOf _.templateSettings
       * @type {Object}
       */
      'imports': {

        /**
         * A reference to the `lodash` function.
         *
         * @memberOf _.templateSettings.imports
         * @type {Function}
         */
        '_': lodash
      }
    };

    // Ensure wrappers are instances of `baseLodash`.
    lodash.prototype = baseLodash.prototype;
    lodash.prototype.constructor = lodash;

    LodashWrapper.prototype = baseCreate(baseLodash.prototype);
    LodashWrapper.prototype.constructor = LodashWrapper;

    /*------------------------------------------------------------------------*/

    /**
     * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
     *
     * @private
     * @constructor
     * @param {*} value The value to wrap.
     */
    function LazyWrapper(value) {
      this.__wrapped__ = value;
      this.__actions__ = [];
      this.__dir__ = 1;
      this.__filtered__ = false;
      this.__iteratees__ = [];
      this.__takeCount__ = MAX_ARRAY_LENGTH;
      this.__views__ = [];
    }

    /**
     * Creates a clone of the lazy wrapper object.
     *
     * @private
     * @name clone
     * @memberOf LazyWrapper
     * @returns {Object} Returns the cloned `LazyWrapper` object.
     */
    function lazyClone() {
      var result = new LazyWrapper(this.__wrapped__);
      result.__actions__ = copyArray(this.__actions__);
      result.__dir__ = this.__dir__;
      result.__filtered__ = this.__filtered__;
      result.__iteratees__ = copyArray(this.__iteratees__);
      result.__takeCount__ = this.__takeCount__;
      result.__views__ = copyArray(this.__views__);
      return result;
    }

    /**
     * Reverses the direction of lazy iteration.
     *
     * @private
     * @name reverse
     * @memberOf LazyWrapper
     * @returns {Object} Returns the new reversed `LazyWrapper` object.
     */
    function lazyReverse() {
      if (this.__filtered__) {
        var result = new LazyWrapper(this);
        result.__dir__ = -1;
        result.__filtered__ = true;
      } else {
        result = this.clone();
        result.__dir__ *= -1;
      }
      return result;
    }

    /**
     * Extracts the unwrapped value from its lazy wrapper.
     *
     * @private
     * @name value
     * @memberOf LazyWrapper
     * @returns {*} Returns the unwrapped value.
     */
    function lazyValue() {
      var array = this.__wrapped__.value(),
          dir = this.__dir__,
          isArr = isArray(array),
          isRight = dir < 0,
          arrLength = isArr ? array.length : 0,
          view = getView(0, arrLength, this.__views__),
          start = view.start,
          end = view.end,
          length = end - start,
          index = isRight ? end : (start - 1),
          iteratees = this.__iteratees__,
          iterLength = iteratees.length,
          resIndex = 0,
          takeCount = nativeMin(length, this.__takeCount__);

      if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
        return baseWrapperValue(array, this.__actions__);
      }
      var result = [];

      outer:
      while (length-- && resIndex < takeCount) {
        index += dir;

        var iterIndex = -1,
            value = array[index];

        while (++iterIndex < iterLength) {
          var data = iteratees[iterIndex],
              iteratee = data.iteratee,
              type = data.type,
              computed = iteratee(value);

          if (type == LAZY_MAP_FLAG) {
            value = computed;
          } else if (!computed) {
            if (type == LAZY_FILTER_FLAG) {
              continue outer;
            } else {
              break outer;
            }
          }
        }
        result[resIndex++] = value;
      }
      return result;
    }

    // Ensure `LazyWrapper` is an instance of `baseLodash`.
    LazyWrapper.prototype = baseCreate(baseLodash.prototype);
    LazyWrapper.prototype.constructor = LazyWrapper;

    /*------------------------------------------------------------------------*/

    /**
     * Creates a hash object.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */
    function Hash(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;

      this.clear();
      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    }

    /**
     * Removes all key-value entries from the hash.
     *
     * @private
     * @name clear
     * @memberOf Hash
     */
    function hashClear() {
      this.__data__ = nativeCreate ? nativeCreate(null) : {};
      this.size = 0;
    }

    /**
     * Removes `key` and its value from the hash.
     *
     * @private
     * @name delete
     * @memberOf Hash
     * @param {Object} hash The hash to modify.
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */
    function hashDelete(key) {
      var result = this.has(key) && delete this.__data__[key];
      this.size -= result ? 1 : 0;
      return result;
    }

    /**
     * Gets the hash value for `key`.
     *
     * @private
     * @name get
     * @memberOf Hash
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */
    function hashGet(key) {
      var data = this.__data__;
      if (nativeCreate) {
        var result = data[key];
        return result === HASH_UNDEFINED ? undefined : result;
      }
      return hasOwnProperty.call(data, key) ? data[key] : undefined;
    }

    /**
     * Checks if a hash value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf Hash
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */
    function hashHas(key) {
      var data = this.__data__;
      return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
    }

    /**
     * Sets the hash `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf Hash
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the hash instance.
     */
    function hashSet(key, value) {
      var data = this.__data__;
      this.size += this.has(key) ? 0 : 1;
      data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
      return this;
    }

    // Add methods to `Hash`.
    Hash.prototype.clear = hashClear;
    Hash.prototype['delete'] = hashDelete;
    Hash.prototype.get = hashGet;
    Hash.prototype.has = hashHas;
    Hash.prototype.set = hashSet;

    /*------------------------------------------------------------------------*/

    /**
     * Creates an list cache object.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */
    function ListCache(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;

      this.clear();
      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    }

    /**
     * Removes all key-value entries from the list cache.
     *
     * @private
     * @name clear
     * @memberOf ListCache
     */
    function listCacheClear() {
      this.__data__ = [];
      this.size = 0;
    }

    /**
     * Removes `key` and its value from the list cache.
     *
     * @private
     * @name delete
     * @memberOf ListCache
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */
    function listCacheDelete(key) {
      var data = this.__data__,
          index = assocIndexOf(data, key);

      if (index < 0) {
        return false;
      }
      var lastIndex = data.length - 1;
      if (index == lastIndex) {
        data.pop();
      } else {
        splice.call(data, index, 1);
      }
      --this.size;
      return true;
    }

    /**
     * Gets the list cache value for `key`.
     *
     * @private
     * @name get
     * @memberOf ListCache
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */
    function listCacheGet(key) {
      var data = this.__data__,
          index = assocIndexOf(data, key);

      return index < 0 ? undefined : data[index][1];
    }

    /**
     * Checks if a list cache value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf ListCache
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */
    function listCacheHas(key) {
      return assocIndexOf(this.__data__, key) > -1;
    }

    /**
     * Sets the list cache `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf ListCache
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the list cache instance.
     */
    function listCacheSet(key, value) {
      var data = this.__data__,
          index = assocIndexOf(data, key);

      if (index < 0) {
        ++this.size;
        data.push([key, value]);
      } else {
        data[index][1] = value;
      }
      return this;
    }

    // Add methods to `ListCache`.
    ListCache.prototype.clear = listCacheClear;
    ListCache.prototype['delete'] = listCacheDelete;
    ListCache.prototype.get = listCacheGet;
    ListCache.prototype.has = listCacheHas;
    ListCache.prototype.set = listCacheSet;

    /*------------------------------------------------------------------------*/

    /**
     * Creates a map cache object to store key-value pairs.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */
    function MapCache(entries) {
      var index = -1,
          length = entries == null ? 0 : entries.length;

      this.clear();
      while (++index < length) {
        var entry = entries[index];
        this.set(entry[0], entry[1]);
      }
    }

    /**
     * Removes all key-value entries from the map.
     *
     * @private
     * @name clear
     * @memberOf MapCache
     */
    function mapCacheClear() {
      this.size = 0;
      this.__data__ = {
        'hash': new Hash,
        'map': new (Map || ListCache),
        'string': new Hash
      };
    }

    /**
     * Removes `key` and its value from the map.
     *
     * @private
     * @name delete
     * @memberOf MapCache
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */
    function mapCacheDelete(key) {
      var result = getMapData(this, key)['delete'](key);
      this.size -= result ? 1 : 0;
      return result;
    }

    /**
     * Gets the map value for `key`.
     *
     * @private
     * @name get
     * @memberOf MapCache
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */
    function mapCacheGet(key) {
      return getMapData(this, key).get(key);
    }

    /**
     * Checks if a map value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf MapCache
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */
    function mapCacheHas(key) {
      return getMapData(this, key).has(key);
    }

    /**
     * Sets the map `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf MapCache
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the map cache instance.
     */
    function mapCacheSet(key, value) {
      var data = getMapData(this, key),
          size = data.size;

      data.set(key, value);
      this.size += data.size == size ? 0 : 1;
      return this;
    }

    // Add methods to `MapCache`.
    MapCache.prototype.clear = mapCacheClear;
    MapCache.prototype['delete'] = mapCacheDelete;
    MapCache.prototype.get = mapCacheGet;
    MapCache.prototype.has = mapCacheHas;
    MapCache.prototype.set = mapCacheSet;

    /*------------------------------------------------------------------------*/

    /**
     *
     * Creates an array cache object to store unique values.
     *
     * @private
     * @constructor
     * @param {Array} [values] The values to cache.
     */
    function SetCache(values) {
      var index = -1,
          length = values == null ? 0 : values.length;

      this.__data__ = new MapCache;
      while (++index < length) {
        this.add(values[index]);
      }
    }

    /**
     * Adds `value` to the array cache.
     *
     * @private
     * @name add
     * @memberOf SetCache
     * @alias push
     * @param {*} value The value to cache.
     * @returns {Object} Returns the cache instance.
     */
    function setCacheAdd(value) {
      this.__data__.set(value, HASH_UNDEFINED);
      return this;
    }

    /**
     * Checks if `value` is in the array cache.
     *
     * @private
     * @name has
     * @memberOf SetCache
     * @param {*} value The value to search for.
     * @returns {number} Returns `true` if `value` is found, else `false`.
     */
    function setCacheHas(value) {
      return this.__data__.has(value);
    }

    // Add methods to `SetCache`.
    SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
    SetCache.prototype.has = setCacheHas;

    /*------------------------------------------------------------------------*/

    /**
     * Creates a stack cache object to store key-value pairs.
     *
     * @private
     * @constructor
     * @param {Array} [entries] The key-value pairs to cache.
     */
    function Stack(entries) {
      var data = this.__data__ = new ListCache(entries);
      this.size = data.size;
    }

    /**
     * Removes all key-value entries from the stack.
     *
     * @private
     * @name clear
     * @memberOf Stack
     */
    function stackClear() {
      this.__data__ = new ListCache;
      this.size = 0;
    }

    /**
     * Removes `key` and its value from the stack.
     *
     * @private
     * @name delete
     * @memberOf Stack
     * @param {string} key The key of the value to remove.
     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
     */
    function stackDelete(key) {
      var data = this.__data__,
          result = data['delete'](key);

      this.size = data.size;
      return result;
    }

    /**
     * Gets the stack value for `key`.
     *
     * @private
     * @name get
     * @memberOf Stack
     * @param {string} key The key of the value to get.
     * @returns {*} Returns the entry value.
     */
    function stackGet(key) {
      return this.__data__.get(key);
    }

    /**
     * Checks if a stack value for `key` exists.
     *
     * @private
     * @name has
     * @memberOf Stack
     * @param {string} key The key of the entry to check.
     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
     */
    function stackHas(key) {
      return this.__data__.has(key);
    }

    /**
     * Sets the stack `key` to `value`.
     *
     * @private
     * @name set
     * @memberOf Stack
     * @param {string} key The key of the value to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns the stack cache instance.
     */
    function stackSet(key, value) {
      var data = this.__data__;
      if (data instanceof ListCache) {
        var pairs = data.__data__;
        if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
          pairs.push([key, value]);
          this.size = ++data.size;
          return this;
        }
        data = this.__data__ = new MapCache(pairs);
      }
      data.set(key, value);
      this.size = data.size;
      return this;
    }

    // Add methods to `Stack`.
    Stack.prototype.clear = stackClear;
    Stack.prototype['delete'] = stackDelete;
    Stack.prototype.get = stackGet;
    Stack.prototype.has = stackHas;
    Stack.prototype.set = stackSet;

    /*------------------------------------------------------------------------*/

    /**
     * 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) {
      var isArr = isArray(value),
          isArg = !isArr && isArguments(value),
          isBuff = !isArr && !isArg && isBuffer(value),
          isType = !isArr && !isArg && !isBuff && isTypedArray(value),
          skipIndexes = isArr || isArg || isBuff || isType,
          result = skipIndexes ? baseTimes(value.length, String) : [],
          length = result.length;

      for (var key in value) {
        if ((inherited || hasOwnProperty.call(value, key)) &&
            !(skipIndexes && (
               // Safari 9 has enumerable `arguments.length` in strict mode.
               key == 'length' ||
               // Node.js 0.10 has enumerable non-index properties on buffers.
               (isBuff && (key == 'offset' || key == 'parent')) ||
               // PhantomJS 2 has enumerable non-index properties on typed arrays.
               (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
               // Skip index properties.
               isIndex(key, length)
            ))) {
          result.push(key);
        }
      }
      return result;
    }

    /**
     * A specialized version of `_.sample` for arrays.
     *
     * @private
     * @param {Array} array The array to sample.
     * @returns {*} Returns the random element.
     */
    function arraySample(array) {
      var length = array.length;
      return length ? array[baseRandom(0, length - 1)] : undefined;
    }

    /**
     * A specialized version of `_.sampleSize` for arrays.
     *
     * @private
     * @param {Array} array The array to sample.
     * @param {number} n The number of elements to sample.
     * @returns {Array} Returns the random elements.
     */
    function arraySampleSize(array, n) {
      return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
    }

    /**
     * A specialized version of `_.shuffle` for arrays.
     *
     * @private
     * @param {Array} array The array to shuffle.
     * @returns {Array} Returns the new shuffled array.
     */
    function arrayShuffle(array) {
      return shuffleSelf(copyArray(array));
    }

    /**
     * This function is like `assignValue` except that it doesn't assign
     * `undefined` values.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */
    function assignMergeValue(object, key, value) {
      if ((value !== undefined && !eq(object[key], value)) ||
          (value === undefined && !(key in object))) {
        baseAssignValue(object, key, value);
      }
    }

    /**
     * Assigns `value` to `key` of `object` if the existing value is not equivalent
     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */
    function assignValue(object, key, value) {
      var objValue = object[key];
      if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
          (value === undefined && !(key in object))) {
        baseAssignValue(object, key, value);
      }
    }

    /**
     * Gets the index at which the `key` is found in `array` of key-value pairs.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {*} key The key to search for.
     * @returns {number} Returns the index of the matched value, else `-1`.
     */
    function assocIndexOf(array, key) {
      var length = array.length;
      while (length--) {
        if (eq(array[length][0], key)) {
          return length;
        }
      }
      return -1;
    }

    /**
     * Aggregates elements of `collection` on `accumulator` with keys transformed
     * by `iteratee` and values set by `setter`.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} setter The function to set `accumulator` values.
     * @param {Function} iteratee The iteratee to transform keys.
     * @param {Object} accumulator The initial aggregated object.
     * @returns {Function} Returns `accumulator`.
     */
    function baseAggregator(collection, setter, iteratee, accumulator) {
      baseEach(collection, function(value, key, collection) {
        setter(accumulator, value, iteratee(value), collection);
      });
      return accumulator;
    }

    /**
     * The base implementation of `_.assign` without support for multiple sources
     * or `customizer` functions.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @returns {Object} Returns `object`.
     */
    function baseAssign(object, source) {
      return object && copyObject(source, keys(source), object);
    }

    /**
     * The base implementation of `_.assignIn` without support for multiple sources
     * or `customizer` functions.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @returns {Object} Returns `object`.
     */
    function baseAssignIn(object, source) {
      return object && copyObject(source, keysIn(source), object);
    }

    /**
     * The base implementation of `assignValue` and `assignMergeValue` without
     * value checks.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {string} key The key of the property to assign.
     * @param {*} value The value to assign.
     */
    function baseAssignValue(object, key, value) {
      if (key == '__proto__' && defineProperty) {
        defineProperty(object, key, {
          'configurable': true,
          'enumerable': true,
          'value': value,
          'writable': true
        });
      } else {
        object[key] = value;
      }
    }

    /**
     * The base implementation of `_.at` without support for individual paths.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {string[]} paths The property paths to pick.
     * @returns {Array} Returns the picked elements.
     */
    function baseAt(object, paths) {
      var index = -1,
          length = paths.length,
          result = Array(length),
          skip = object == null;

      while (++index < length) {
        result[index] = skip ? undefined : get(object, paths[index]);
      }
      return result;
    }

    /**
     * The base implementation of `_.clamp` which doesn't coerce arguments.
     *
     * @private
     * @param {number} number The number to clamp.
     * @param {number} [lower] The lower bound.
     * @param {number} upper The upper bound.
     * @returns {number} Returns the clamped number.
     */
    function baseClamp(number, lower, upper) {
      if (number === number) {
        if (upper !== undefined) {
          number = number <= upper ? number : upper;
        }
        if (lower !== undefined) {
          number = number >= lower ? number : lower;
        }
      }
      return number;
    }

    /**
     * The base implementation of `_.clone` and `_.cloneDeep` which tracks
     * traversed objects.
     *
     * @private
     * @param {*} value The value to clone.
     * @param {boolean} bitmask The bitmask flags.
     *  1 - Deep clone
     *  2 - Flatten inherited properties
     *  4 - Clone symbols
     * @param {Function} [customizer] The function to customize cloning.
     * @param {string} [key] The key of `value`.
     * @param {Object} [object] The parent object of `value`.
     * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
     * @returns {*} Returns the cloned value.
     */
    function baseClone(value, bitmask, customizer, key, object, stack) {
      var result,
          isDeep = bitmask & CLONE_DEEP_FLAG,
          isFlat = bitmask & CLONE_FLAT_FLAG,
          isFull = bitmask & CLONE_SYMBOLS_FLAG;

      if (customizer) {
        result = object ? customizer(value, key, object, stack) : customizer(value);
      }
      if (result !== undefined) {
        return result;
      }
      if (!isObject(value)) {
        return value;
      }
      var isArr = isArray(value);
      if (isArr) {
        result = initCloneArray(value);
        if (!isDeep) {
          return copyArray(value, result);
        }
      } else {
        var tag = getTag(value),
            isFunc = tag == funcTag || tag == genTag;

        if (isBuffer(value)) {
          return cloneBuffer(value, isDeep);
        }
        if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
          result = (isFlat || isFunc) ? {} : initCloneObject(value);
          if (!isDeep) {
            return isFlat
              ? copySymbolsIn(value, baseAssignIn(result, value))
              : copySymbols(value, baseAssign(result, value));
          }
        } else {
          if (!cloneableTags[tag]) {
            return object ? value : {};
          }
          result = initCloneByTag(value, tag, isDeep);
        }
      }
      // Check for circular references and return its corresponding clone.
      stack || (stack = new Stack);
      var stacked = stack.get(value);
      if (stacked) {
        return stacked;
      }
      stack.set(value, result);

      if (isSet(value)) {
        value.forEach(function(subValue) {
          result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
        });
      } else if (isMap(value)) {
        value.forEach(function(subValue, key) {
          result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
        });
      }

      var keysFunc = isFull
        ? (isFlat ? getAllKeysIn : getAllKeys)
        : (isFlat ? keysIn : keys);

      var props = isArr ? undefined : keysFunc(value);
      arrayEach(props || value, function(subValue, key) {
        if (props) {
          key = subValue;
          subValue = value[key];
        }
        // Recursively populate clone (susceptible to call stack limits).
        assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
      });
      return result;
    }

    /**
     * The base implementation of `_.conforms` which doesn't clone `source`.
     *
     * @private
     * @param {Object} source The object of property predicates to conform to.
     * @returns {Function} Returns the new spec function.
     */
    function baseConforms(source) {
      var props = keys(source);
      return function(object) {
        return baseConformsTo(object, source, props);
      };
    }

    /**
     * The base implementation of `_.conformsTo` which accepts `props` to check.
     *
     * @private
     * @param {Object} object The object to inspect.
     * @param {Object} source The object of property predicates to conform to.
     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
     */
    function baseConformsTo(object, source, props) {
      var length = props.length;
      if (object == null) {
        return !length;
      }
      object = Object(object);
      while (length--) {
        var key = props[length],
            predicate = source[key],
            value = object[key];

        if ((value === undefined && !(key in object)) || !predicate(value)) {
          return false;
        }
      }
      return true;
    }

    /**
     * The base implementation of `_.delay` and `_.defer` which accepts `args`
     * to provide to `func`.
     *
     * @private
     * @param {Function} func The function to delay.
     * @param {number} wait The number of milliseconds to delay invocation.
     * @param {Array} args The arguments to provide to `func`.
     * @returns {number|Object} Returns the timer id or timeout object.
     */
    function baseDelay(func, wait, args) {
      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      return setTimeout(function() { func.apply(undefined, args); }, wait);
    }

    /**
     * The base implementation of methods like `_.difference` without support
     * for excluding multiple arrays or iteratee shorthands.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {Array} values The values to exclude.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of filtered values.
     */
    function baseDifference(array, values, iteratee, comparator) {
      var index = -1,
          includes = arrayIncludes,
          isCommon = true,
          length = array.length,
          result = [],
          valuesLength = values.length;

      if (!length) {
        return result;
      }
      if (iteratee) {
        values = arrayMap(values, baseUnary(iteratee));
      }
      if (comparator) {
        includes = arrayIncludesWith;
        isCommon = false;
      }
      else if (values.length >= LARGE_ARRAY_SIZE) {
        includes = cacheHas;
        isCommon = false;
        values = new SetCache(values);
      }
      outer:
      while (++index < length) {
        var value = array[index],
            computed = iteratee == null ? value : iteratee(value);

        value = (comparator || value !== 0) ? value : 0;
        if (isCommon && computed === computed) {
          var valuesIndex = valuesLength;
          while (valuesIndex--) {
            if (values[valuesIndex] === computed) {
              continue outer;
            }
          }
          result.push(value);
        }
        else if (!includes(values, computed, comparator)) {
          result.push(value);
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.forEach` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array|Object} Returns `collection`.
     */
    var baseEach = createBaseEach(baseForOwn);

    /**
     * The base implementation of `_.forEachRight` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array|Object} Returns `collection`.
     */
    var baseEachRight = createBaseEach(baseForOwnRight, true);

    /**
     * The base implementation of `_.every` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} predicate The function invoked per iteration.
     * @returns {boolean} Returns `true` if all elements pass the predicate check,
     *  else `false`
     */
    function baseEvery(collection, predicate) {
      var result = true;
      baseEach(collection, function(value, index, collection) {
        result = !!predicate(value, index, collection);
        return result;
      });
      return result;
    }

    /**
     * The base implementation of methods like `_.max` and `_.min` which accepts a
     * `comparator` to determine the extremum value.
     *
     * @private
     * @param {Array} array The array to iterate over.
     * @param {Function} iteratee The iteratee invoked per iteration.
     * @param {Function} comparator The comparator used to compare values.
     * @returns {*} Returns the extremum value.
     */
    function baseExtremum(array, iteratee, comparator) {
      var index = -1,
          length = array.length;

      while (++index < length) {
        var value = array[index],
            current = iteratee(value);

        if (current != null && (computed === undefined
              ? (current === current && !isSymbol(current))
              : comparator(current, computed)
            )) {
          var computed = current,
              result = value;
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.fill` without an iteratee call guard.
     *
     * @private
     * @param {Array} array The array to fill.
     * @param {*} value The value to fill `array` with.
     * @param {number} [start=0] The start position.
     * @param {number} [end=array.length] The end position.
     * @returns {Array} Returns `array`.
     */
    function baseFill(array, value, start, end) {
      var length = array.length;

      start = toInteger(start);
      if (start < 0) {
        start = -start > length ? 0 : (length + start);
      }
      end = (end === undefined || end > length) ? length : toInteger(end);
      if (end < 0) {
        end += length;
      }
      end = start > end ? 0 : toLength(end);
      while (start < end) {
        array[start++] = value;
      }
      return array;
    }

    /**
     * The base implementation of `_.filter` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} predicate The function invoked per iteration.
     * @returns {Array} Returns the new filtered array.
     */
    function baseFilter(collection, predicate) {
      var result = [];
      baseEach(collection, function(value, index, collection) {
        if (predicate(value, index, collection)) {
          result.push(value);
        }
      });
      return result;
    }

    /**
     * The base implementation of `_.flatten` with support for restricting flattening.
     *
     * @private
     * @param {Array} array The array to flatten.
     * @param {number} depth The maximum recursion depth.
     * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
     * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
     * @param {Array} [result=[]] The initial result value.
     * @returns {Array} Returns the new flattened array.
     */
    function baseFlatten(array, depth, predicate, isStrict, result) {
      var index = -1,
          length = array.length;

      predicate || (predicate = isFlattenable);
      result || (result = []);

      while (++index < length) {
        var value = array[index];
        if (depth > 0 && predicate(value)) {
          if (depth > 1) {
            // Recursively flatten arrays (susceptible to call stack limits).
            baseFlatten(value, depth - 1, predicate, isStrict, result);
          } else {
            arrayPush(result, value);
          }
        } else if (!isStrict) {
          result[result.length] = value;
        }
      }
      return result;
    }

    /**
     * The base implementation of `baseForOwn` which iterates over `object`
     * properties returned by `keysFunc` and invokes `iteratee` for each property.
     * Iteratee functions may exit iteration early by explicitly returning `false`.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @param {Function} keysFunc The function to get the keys of `object`.
     * @returns {Object} Returns `object`.
     */
    var baseFor = createBaseFor();

    /**
     * This function is like `baseFor` except that it iterates over properties
     * in the opposite order.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @param {Function} keysFunc The function to get the keys of `object`.
     * @returns {Object} Returns `object`.
     */
    var baseForRight = createBaseFor(true);

    /**
     * The base implementation of `_.forOwn` without support for iteratee shorthands.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Object} Returns `object`.
     */
    function baseForOwn(object, iteratee) {
      return object && baseFor(object, iteratee, keys);
    }

    /**
     * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Object} Returns `object`.
     */
    function baseForOwnRight(object, iteratee) {
      return object && baseForRight(object, iteratee, keys);
    }

    /**
     * The base implementation of `_.functions` which creates an array of
     * `object` function property names filtered from `props`.
     *
     * @private
     * @param {Object} object The object to inspect.
     * @param {Array} props The property names to filter.
     * @returns {Array} Returns the function names.
     */
    function baseFunctions(object, props) {
      return arrayFilter(props, function(key) {
        return isFunction(object[key]);
      });
    }

    /**
     * The base implementation of `_.get` without support for default values.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the property to get.
     * @returns {*} Returns the resolved value.
     */
    function baseGet(object, path) {
      path = castPath(path, object);

      var index = 0,
          length = path.length;

      while (object != null && index < length) {
        object = object[toKey(path[index++])];
      }
      return (index && index == length) ? object : undefined;
    }

    /**
     * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
     * `keysFunc` and `symbolsFunc` to get the enumerable property names and
     * symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Function} keysFunc The function to get the keys of `object`.
     * @param {Function} symbolsFunc The function to get the symbols of `object`.
     * @returns {Array} Returns the array of property names and symbols.
     */
    function baseGetAllKeys(object, keysFunc, symbolsFunc) {
      var result = keysFunc(object);
      return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
    }

    /**
     * The base implementation of `getTag` without fallbacks for buggy environments.
     *
     * @private
     * @param {*} value The value to query.
     * @returns {string} Returns the `toStringTag`.
     */
    function baseGetTag(value) {
      if (value == null) {
        return value === undefined ? undefinedTag : nullTag;
      }
      return (symToStringTag && symToStringTag in Object(value))
        ? getRawTag(value)
        : objectToString(value);
    }

    /**
     * The base implementation of `_.gt` which doesn't coerce arguments.
     *
     * @private
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is greater than `other`,
     *  else `false`.
     */
    function baseGt(value, other) {
      return value > other;
    }

    /**
     * The base implementation of `_.has` without support for deep paths.
     *
     * @private
     * @param {Object} [object] The object to query.
     * @param {Array|string} key The key to check.
     * @returns {boolean} Returns `true` if `key` exists, else `false`.
     */
    function baseHas(object, key) {
      return object != null && hasOwnProperty.call(object, key);
    }

    /**
     * The base implementation of `_.hasIn` without support for deep paths.
     *
     * @private
     * @param {Object} [object] The object to query.
     * @param {Array|string} key The key to check.
     * @returns {boolean} Returns `true` if `key` exists, else `false`.
     */
    function baseHasIn(object, key) {
      return object != null && key in Object(object);
    }

    /**
     * The base implementation of `_.inRange` which doesn't coerce arguments.
     *
     * @private
     * @param {number} number The number to check.
     * @param {number} start The start of the range.
     * @param {number} end The end of the range.
     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
     */
    function baseInRange(number, start, end) {
      return number >= nativeMin(start, end) && number < nativeMax(start, end);
    }

    /**
     * The base implementation of methods like `_.intersection`, without support
     * for iteratee shorthands, that accepts an array of arrays to inspect.
     *
     * @private
     * @param {Array} arrays The arrays to inspect.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of shared values.
     */
    function baseIntersection(arrays, iteratee, comparator) {
      var includes = comparator ? arrayIncludesWith : arrayIncludes,
          length = arrays[0].length,
          othLength = arrays.length,
          othIndex = othLength,
          caches = Array(othLength),
          maxLength = Infinity,
          result = [];

      while (othIndex--) {
        var array = arrays[othIndex];
        if (othIndex && iteratee) {
          array = arrayMap(array, baseUnary(iteratee));
        }
        maxLength = nativeMin(array.length, maxLength);
        caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
          ? new SetCache(othIndex && array)
          : undefined;
      }
      array = arrays[0];

      var index = -1,
          seen = caches[0];

      outer:
      while (++index < length && result.length < maxLength) {
        var value = array[index],
            computed = iteratee ? iteratee(value) : value;

        value = (comparator || value !== 0) ? value : 0;
        if (!(seen
              ? cacheHas(seen, computed)
              : includes(result, computed, comparator)
            )) {
          othIndex = othLength;
          while (--othIndex) {
            var cache = caches[othIndex];
            if (!(cache
                  ? cacheHas(cache, computed)
                  : includes(arrays[othIndex], computed, comparator))
                ) {
              continue outer;
            }
          }
          if (seen) {
            seen.push(computed);
          }
          result.push(value);
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.invert` and `_.invertBy` which inverts
     * `object` with values transformed by `iteratee` and set by `setter`.
     *
     * @private
     * @param {Object} object The object to iterate over.
     * @param {Function} setter The function to set `accumulator` values.
     * @param {Function} iteratee The iteratee to transform values.
     * @param {Object} accumulator The initial inverted object.
     * @returns {Function} Returns `accumulator`.
     */
    function baseInverter(object, setter, iteratee, accumulator) {
      baseForOwn(object, function(value, key, object) {
        setter(accumulator, iteratee(value), key, object);
      });
      return accumulator;
    }

    /**
     * The base implementation of `_.invoke` without support for individual
     * method arguments.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the method to invoke.
     * @param {Array} args The arguments to invoke the method with.
     * @returns {*} Returns the result of the invoked method.
     */
    function baseInvoke(object, path, args) {
      path = castPath(path, object);
      object = parent(object, path);
      var func = object == null ? object : object[toKey(last(path))];
      return func == null ? undefined : apply(func, object, args);
    }

    /**
     * The base implementation of `_.isArguments`.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
     */
    function baseIsArguments(value) {
      return isObjectLike(value) && baseGetTag(value) == argsTag;
    }

    /**
     * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
     */
    function baseIsArrayBuffer(value) {
      return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
    }

    /**
     * The base implementation of `_.isDate` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
     */
    function baseIsDate(value) {
      return isObjectLike(value) && baseGetTag(value) == dateTag;
    }

    /**
     * The base implementation of `_.isEqual` which supports partial comparisons
     * and tracks traversed objects.
     *
     * @private
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @param {boolean} bitmask The bitmask flags.
     *  1 - Unordered comparison
     *  2 - Partial comparison
     * @param {Function} [customizer] The function to customize comparisons.
     * @param {Object} [stack] Tracks traversed `value` and `other` objects.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     */
    function baseIsEqual(value, other, bitmask, customizer, stack) {
      if (value === other) {
        return true;
      }
      if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
        return value !== value && other !== other;
      }
      return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
    }

    /**
     * A specialized version of `baseIsEqual` for arrays and objects which performs
     * deep comparisons and tracks traversed objects enabling objects with circular
     * references to be compared.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} [stack] Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */
    function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
      var objIsArr = isArray(object),
          othIsArr = isArray(other),
          objTag = objIsArr ? arrayTag : getTag(object),
          othTag = othIsArr ? arrayTag : getTag(other);

      objTag = objTag == argsTag ? objectTag : objTag;
      othTag = othTag == argsTag ? objectTag : othTag;

      var objIsObj = objTag == objectTag,
          othIsObj = othTag == objectTag,
          isSameTag = objTag == othTag;

      if (isSameTag && isBuffer(object)) {
        if (!isBuffer(other)) {
          return false;
        }
        objIsArr = true;
        objIsObj = false;
      }
      if (isSameTag && !objIsObj) {
        stack || (stack = new Stack);
        return (objIsArr || isTypedArray(object))
          ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
          : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
      }
      if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
        var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
            othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

        if (objIsWrapped || othIsWrapped) {
          var objUnwrapped = objIsWrapped ? object.value() : object,
              othUnwrapped = othIsWrapped ? other.value() : other;

          stack || (stack = new Stack);
          return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
        }
      }
      if (!isSameTag) {
        return false;
      }
      stack || (stack = new Stack);
      return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
    }

    /**
     * The base implementation of `_.isMap` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
     */
    function baseIsMap(value) {
      return isObjectLike(value) && getTag(value) == mapTag;
    }

    /**
     * The base implementation of `_.isMatch` without support for iteratee shorthands.
     *
     * @private
     * @param {Object} object The object to inspect.
     * @param {Object} source The object of property values to match.
     * @param {Array} matchData The property names, values, and compare flags to match.
     * @param {Function} [customizer] The function to customize comparisons.
     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
     */
    function baseIsMatch(object, source, matchData, customizer) {
      var index = matchData.length,
          length = index,
          noCustomizer = !customizer;

      if (object == null) {
        return !length;
      }
      object = Object(object);
      while (index--) {
        var data = matchData[index];
        if ((noCustomizer && data[2])
              ? data[1] !== object[data[0]]
              : !(data[0] in object)
            ) {
          return false;
        }
      }
      while (++index < length) {
        data = matchData[index];
        var key = data[0],
            objValue = object[key],
            srcValue = data[1];

        if (noCustomizer && data[2]) {
          if (objValue === undefined && !(key in object)) {
            return false;
          }
        } else {
          var stack = new Stack;
          if (customizer) {
            var result = customizer(objValue, srcValue, key, object, source, stack);
          }
          if (!(result === undefined
                ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
                : result
              )) {
            return false;
          }
        }
      }
      return true;
    }

    /**
     * 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) ? reIsNative : reIsHostCtor;
      return pattern.test(toSource(value));
    }

    /**
     * The base implementation of `_.isRegExp` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
     */
    function baseIsRegExp(value) {
      return isObjectLike(value) && baseGetTag(value) == regexpTag;
    }

    /**
     * The base implementation of `_.isSet` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
     */
    function baseIsSet(value) {
      return isObjectLike(value) && getTag(value) == setTag;
    }

    /**
     * The base implementation of `_.isTypedArray` without Node.js optimizations.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
     */
    function baseIsTypedArray(value) {
      return isObjectLike(value) &&
        isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
    }

    /**
     * The base implementation of `_.iteratee`.
     *
     * @private
     * @param {*} [value=_.identity] The value to convert to an iteratee.
     * @returns {Function} Returns the iteratee.
     */
    function baseIteratee(value) {
      // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
      // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
      if (typeof value == 'function') {
        return value;
      }
      if (value == null) {
        return identity;
      }
      if (typeof value == 'object') {
        return isArray(value)
          ? baseMatchesProperty(value[0], value[1])
          : baseMatches(value);
      }
      return property(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;
    }

    /**
     * The base implementation of `_.keysIn` 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 baseKeysIn(object) {
      if (!isObject(object)) {
        return nativeKeysIn(object);
      }
      var isProto = isPrototype(object),
          result = [];

      for (var key in object) {
        if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
          result.push(key);
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.lt` which doesn't coerce arguments.
     *
     * @private
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is less than `other`,
     *  else `false`.
     */
    function baseLt(value, other) {
      return value < other;
    }

    /**
     * The base implementation of `_.map` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} iteratee The function invoked per iteration.
     * @returns {Array} Returns the new mapped array.
     */
    function baseMap(collection, iteratee) {
      var index = -1,
          result = isArrayLike(collection) ? Array(collection.length) : [];

      baseEach(collection, function(value, key, collection) {
        result[++index] = iteratee(value, key, collection);
      });
      return result;
    }

    /**
     * The base implementation of `_.matches` which doesn't clone `source`.
     *
     * @private
     * @param {Object} source The object of property values to match.
     * @returns {Function} Returns the new spec function.
     */
    function baseMatches(source) {
      var matchData = getMatchData(source);
      if (matchData.length == 1 && matchData[0][2]) {
        return matchesStrictComparable(matchData[0][0], matchData[0][1]);
      }
      return function(object) {
        return object === source || baseIsMatch(object, source, matchData);
      };
    }

    /**
     * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
     *
     * @private
     * @param {string} path The path of the property to get.
     * @param {*} srcValue The value to match.
     * @returns {Function} Returns the new spec function.
     */
    function baseMatchesProperty(path, srcValue) {
      if (isKey(path) && isStrictComparable(srcValue)) {
        return matchesStrictComparable(toKey(path), srcValue);
      }
      return function(object) {
        var objValue = get(object, path);
        return (objValue === undefined && objValue === srcValue)
          ? hasIn(object, path)
          : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
      };
    }

    /**
     * The base implementation of `_.merge` without support for multiple sources.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @param {number} srcIndex The index of `source`.
     * @param {Function} [customizer] The function to customize merged values.
     * @param {Object} [stack] Tracks traversed source values and their merged
     *  counterparts.
     */
    function baseMerge(object, source, srcIndex, customizer, stack) {
      if (object === source) {
        return;
      }
      baseFor(source, function(srcValue, key) {
        stack || (stack = new Stack);
        if (isObject(srcValue)) {
          baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
        }
        else {
          var newValue = customizer
            ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
            : undefined;

          if (newValue === undefined) {
            newValue = srcValue;
          }
          assignMergeValue(object, key, newValue);
        }
      }, keysIn);
    }

    /**
     * A specialized version of `baseMerge` for arrays and objects which performs
     * deep merges and tracks traversed objects enabling objects with circular
     * references to be merged.
     *
     * @private
     * @param {Object} object The destination object.
     * @param {Object} source The source object.
     * @param {string} key The key of the value to merge.
     * @param {number} srcIndex The index of `source`.
     * @param {Function} mergeFunc The function to merge values.
     * @param {Function} [customizer] The function to customize assigned values.
     * @param {Object} [stack] Tracks traversed source values and their merged
     *  counterparts.
     */
    function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
      var objValue = safeGet(object, key),
          srcValue = safeGet(source, key),
          stacked = stack.get(srcValue);

      if (stacked) {
        assignMergeValue(object, key, stacked);
        return;
      }
      var newValue = customizer
        ? customizer(objValue, srcValue, (key + ''), object, source, stack)
        : undefined;

      var isCommon = newValue === undefined;

      if (isCommon) {
        var isArr = isArray(srcValue),
            isBuff = !isArr && isBuffer(srcValue),
            isTyped = !isArr && !isBuff && isTypedArray(srcValue);

        newValue = srcValue;
        if (isArr || isBuff || isTyped) {
          if (isArray(objValue)) {
            newValue = objValue;
          }
          else if (isArrayLikeObject(objValue)) {
            newValue = copyArray(objValue);
          }
          else if (isBuff) {
            isCommon = false;
            newValue = cloneBuffer(srcValue, true);
          }
          else if (isTyped) {
            isCommon = false;
            newValue = cloneTypedArray(srcValue, true);
          }
          else {
            newValue = [];
          }
        }
        else if (isPlainObject(srcValue) || isArguments(srcValue)) {
          newValue = objValue;
          if (isArguments(objValue)) {
            newValue = toPlainObject(objValue);
          }
          else if (!isObject(objValue) || isFunction(objValue)) {
            newValue = initCloneObject(srcValue);
          }
        }
        else {
          isCommon = false;
        }
      }
      if (isCommon) {
        // Recursively merge objects and arrays (susceptible to call stack limits).
        stack.set(srcValue, newValue);
        mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
        stack['delete'](srcValue);
      }
      assignMergeValue(object, key, newValue);
    }

    /**
     * The base implementation of `_.nth` which doesn't coerce arguments.
     *
     * @private
     * @param {Array} array The array to query.
     * @param {number} n The index of the element to return.
     * @returns {*} Returns the nth element of `array`.
     */
    function baseNth(array, n) {
      var length = array.length;
      if (!length) {
        return;
      }
      n += n < 0 ? length : 0;
      return isIndex(n, length) ? array[n] : undefined;
    }

    /**
     * The base implementation of `_.orderBy` without param guards.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
     * @param {string[]} orders The sort orders of `iteratees`.
     * @returns {Array} Returns the new sorted array.
     */
    function baseOrderBy(collection, iteratees, orders) {
      if (iteratees.length) {
        iteratees = arrayMap(iteratees, function(iteratee) {
          if (isArray(iteratee)) {
            return function(value) {
              return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
            }
          }
          return iteratee;
        });
      } else {
        iteratees = [identity];
      }

      var index = -1;
      iteratees = arrayMap(iteratees, baseUnary(getIteratee()));

      var result = baseMap(collection, function(value, key, collection) {
        var criteria = arrayMap(iteratees, function(iteratee) {
          return iteratee(value);
        });
        return { 'criteria': criteria, 'index': ++index, 'value': value };
      });

      return baseSortBy(result, function(object, other) {
        return compareMultiple(object, other, orders);
      });
    }

    /**
     * The base implementation of `_.pick` without support for individual
     * property identifiers.
     *
     * @private
     * @param {Object} object The source object.
     * @param {string[]} paths The property paths to pick.
     * @returns {Object} Returns the new object.
     */
    function basePick(object, paths) {
      return basePickBy(object, paths, function(value, path) {
        return hasIn(object, path);
      });
    }

    /**
     * The base implementation of  `_.pickBy` without support for iteratee shorthands.
     *
     * @private
     * @param {Object} object The source object.
     * @param {string[]} paths The property paths to pick.
     * @param {Function} predicate The function invoked per property.
     * @returns {Object} Returns the new object.
     */
    function basePickBy(object, paths, predicate) {
      var index = -1,
          length = paths.length,
          result = {};

      while (++index < length) {
        var path = paths[index],
            value = baseGet(object, path);

        if (predicate(value, path)) {
          baseSet(result, castPath(path, object), value);
        }
      }
      return result;
    }

    /**
     * A specialized version of `baseProperty` which supports deep paths.
     *
     * @private
     * @param {Array|string} path The path of the property to get.
     * @returns {Function} Returns the new accessor function.
     */
    function basePropertyDeep(path) {
      return function(object) {
        return baseGet(object, path);
      };
    }

    /**
     * The base implementation of `_.pullAllBy` without support for iteratee
     * shorthands.
     *
     * @private
     * @param {Array} array The array to modify.
     * @param {Array} values The values to remove.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns `array`.
     */
    function basePullAll(array, values, iteratee, comparator) {
      var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
          index = -1,
          length = values.length,
          seen = array;

      if (array === values) {
        values = copyArray(values);
      }
      if (iteratee) {
        seen = arrayMap(array, baseUnary(iteratee));
      }
      while (++index < length) {
        var fromIndex = 0,
            value = values[index],
            computed = iteratee ? iteratee(value) : value;

        while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
          if (seen !== array) {
            splice.call(seen, fromIndex, 1);
          }
          splice.call(array, fromIndex, 1);
        }
      }
      return array;
    }

    /**
     * The base implementation of `_.pullAt` without support for individual
     * indexes or capturing the removed elements.
     *
     * @private
     * @param {Array} array The array to modify.
     * @param {number[]} indexes The indexes of elements to remove.
     * @returns {Array} Returns `array`.
     */
    function basePullAt(array, indexes) {
      var length = array ? indexes.length : 0,
          lastIndex = length - 1;

      while (length--) {
        var index = indexes[length];
        if (length == lastIndex || index !== previous) {
          var previous = index;
          if (isIndex(index)) {
            splice.call(array, index, 1);
          } else {
            baseUnset(array, index);
          }
        }
      }
      return array;
    }

    /**
     * The base implementation of `_.random` without support for returning
     * floating-point numbers.
     *
     * @private
     * @param {number} lower The lower bound.
     * @param {number} upper The upper bound.
     * @returns {number} Returns the random number.
     */
    function baseRandom(lower, upper) {
      return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
    }

    /**
     * The base implementation of `_.range` and `_.rangeRight` which doesn't
     * coerce arguments.
     *
     * @private
     * @param {number} start The start of the range.
     * @param {number} end The end of the range.
     * @param {number} step The value to increment or decrement by.
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Array} Returns the range of numbers.
     */
    function baseRange(start, end, step, fromRight) {
      var index = -1,
          length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
          result = Array(length);

      while (length--) {
        result[fromRight ? length : ++index] = start;
        start += step;
      }
      return result;
    }

    /**
     * The base implementation of `_.repeat` which doesn't coerce arguments.
     *
     * @private
     * @param {string} string The string to repeat.
     * @param {number} n The number of times to repeat the string.
     * @returns {string} Returns the repeated string.
     */
    function baseRepeat(string, n) {
      var result = '';
      if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
        return result;
      }
      // Leverage the exponentiation by squaring algorithm for a faster repeat.
      // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
      do {
        if (n % 2) {
          result += string;
        }
        n = nativeFloor(n / 2);
        if (n) {
          string += string;
        }
      } while (n);

      return result;
    }

    /**
     * The base implementation of `_.rest` which doesn't validate or coerce arguments.
     *
     * @private
     * @param {Function} func The function to apply a rest parameter to.
     * @param {number} [start=func.length-1] The start position of the rest parameter.
     * @returns {Function} Returns the new function.
     */
    function baseRest(func, start) {
      return setToString(overRest(func, start, identity), func + '');
    }

    /**
     * The base implementation of `_.sample`.
     *
     * @private
     * @param {Array|Object} collection The collection to sample.
     * @returns {*} Returns the random element.
     */
    function baseSample(collection) {
      return arraySample(values(collection));
    }

    /**
     * The base implementation of `_.sampleSize` without param guards.
     *
     * @private
     * @param {Array|Object} collection The collection to sample.
     * @param {number} n The number of elements to sample.
     * @returns {Array} Returns the random elements.
     */
    function baseSampleSize(collection, n) {
      var array = values(collection);
      return shuffleSelf(array, baseClamp(n, 0, array.length));
    }

    /**
     * The base implementation of `_.set`.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to set.
     * @param {*} value The value to set.
     * @param {Function} [customizer] The function to customize path creation.
     * @returns {Object} Returns `object`.
     */
    function baseSet(object, path, value, customizer) {
      if (!isObject(object)) {
        return object;
      }
      path = castPath(path, object);

      var index = -1,
          length = path.length,
          lastIndex = length - 1,
          nested = object;

      while (nested != null && ++index < length) {
        var key = toKey(path[index]),
            newValue = value;

        if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
          return object;
        }

        if (index != lastIndex) {
          var objValue = nested[key];
          newValue = customizer ? customizer(objValue, key, nested) : undefined;
          if (newValue === undefined) {
            newValue = isObject(objValue)
              ? objValue
              : (isIndex(path[index + 1]) ? [] : {});
          }
        }
        assignValue(nested, key, newValue);
        nested = nested[key];
      }
      return object;
    }

    /**
     * The base implementation of `setData` without support for hot loop shorting.
     *
     * @private
     * @param {Function} func The function to associate metadata with.
     * @param {*} data The metadata.
     * @returns {Function} Returns `func`.
     */
    var baseSetData = !metaMap ? identity : function(func, data) {
      metaMap.set(func, data);
      return func;
    };

    /**
     * The base implementation of `setToString` without support for hot loop shorting.
     *
     * @private
     * @param {Function} func The function to modify.
     * @param {Function} string The `toString` result.
     * @returns {Function} Returns `func`.
     */
    var baseSetToString = !defineProperty ? identity : function(func, string) {
      return defineProperty(func, 'toString', {
        'configurable': true,
        'enumerable': false,
        'value': constant(string),
        'writable': true
      });
    };

    /**
     * The base implementation of `_.shuffle`.
     *
     * @private
     * @param {Array|Object} collection The collection to shuffle.
     * @returns {Array} Returns the new shuffled array.
     */
    function baseShuffle(collection) {
      return shuffleSelf(values(collection));
    }

    /**
     * The base implementation of `_.slice` without an iteratee call guard.
     *
     * @private
     * @param {Array} array The array to slice.
     * @param {number} [start=0] The start position.
     * @param {number} [end=array.length] The end position.
     * @returns {Array} Returns the slice of `array`.
     */
    function baseSlice(array, start, end) {
      var index = -1,
          length = array.length;

      if (start < 0) {
        start = -start > length ? 0 : (length + start);
      }
      end = end > length ? length : end;
      if (end < 0) {
        end += length;
      }
      length = start > end ? 0 : ((end - start) >>> 0);
      start >>>= 0;

      var result = Array(length);
      while (++index < length) {
        result[index] = array[index + start];
      }
      return result;
    }

    /**
     * The base implementation of `_.some` without support for iteratee shorthands.
     *
     * @private
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} predicate The function invoked per iteration.
     * @returns {boolean} Returns `true` if any element passes the predicate check,
     *  else `false`.
     */
    function baseSome(collection, predicate) {
      var result;

      baseEach(collection, function(value, index, collection) {
        result = predicate(value, index, collection);
        return !result;
      });
      return !!result;
    }

    /**
     * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
     * performs a binary search of `array` to determine the index at which `value`
     * should be inserted into `array` in order to maintain its sort order.
     *
     * @private
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @param {boolean} [retHighest] Specify returning the highest qualified index.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     */
    function baseSortedIndex(array, value, retHighest) {
      var low = 0,
          high = array == null ? low : array.length;

      if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
        while (low < high) {
          var mid = (low + high) >>> 1,
              computed = array[mid];

          if (computed !== null && !isSymbol(computed) &&
              (retHighest ? (computed <= value) : (computed < value))) {
            low = mid + 1;
          } else {
            high = mid;
          }
        }
        return high;
      }
      return baseSortedIndexBy(array, value, identity, retHighest);
    }

    /**
     * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
     * which invokes `iteratee` for `value` and each element of `array` to compute
     * their sort ranking. The iteratee is invoked with one argument; (value).
     *
     * @private
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @param {Function} iteratee The iteratee invoked per element.
     * @param {boolean} [retHighest] Specify returning the highest qualified index.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     */
    function baseSortedIndexBy(array, value, iteratee, retHighest) {
      var low = 0,
          high = array == null ? 0 : array.length;
      if (high === 0) {
        return 0;
      }

      value = iteratee(value);
      var valIsNaN = value !== value,
          valIsNull = value === null,
          valIsSymbol = isSymbol(value),
          valIsUndefined = value === undefined;

      while (low < high) {
        var mid = nativeFloor((low + high) / 2),
            computed = iteratee(array[mid]),
            othIsDefined = computed !== undefined,
            othIsNull = computed === null,
            othIsReflexive = computed === computed,
            othIsSymbol = isSymbol(computed);

        if (valIsNaN) {
          var setLow = retHighest || othIsReflexive;
        } else if (valIsUndefined) {
          setLow = othIsReflexive && (retHighest || othIsDefined);
        } else if (valIsNull) {
          setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
        } else if (valIsSymbol) {
          setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
        } else if (othIsNull || othIsSymbol) {
          setLow = false;
        } else {
          setLow = retHighest ? (computed <= value) : (computed < value);
        }
        if (setLow) {
          low = mid + 1;
        } else {
          high = mid;
        }
      }
      return nativeMin(high, MAX_ARRAY_INDEX);
    }

    /**
     * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
     * support for iteratee shorthands.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     */
    function baseSortedUniq(array, iteratee) {
      var index = -1,
          length = array.length,
          resIndex = 0,
          result = [];

      while (++index < length) {
        var value = array[index],
            computed = iteratee ? iteratee(value) : value;

        if (!index || !eq(computed, seen)) {
          var seen = computed;
          result[resIndex++] = value === 0 ? 0 : value;
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.toNumber` which doesn't ensure correct
     * conversions of binary, hexadecimal, or octal string values.
     *
     * @private
     * @param {*} value The value to process.
     * @returns {number} Returns the number.
     */
    function baseToNumber(value) {
      if (typeof value == 'number') {
        return value;
      }
      if (isSymbol(value)) {
        return NAN;
      }
      return +value;
    }

    /**
     * The base implementation of `_.toString` which doesn't convert nullish
     * values to empty strings.
     *
     * @private
     * @param {*} value The value to process.
     * @returns {string} Returns the string.
     */
    function baseToString(value) {
      // Exit early for strings to avoid a performance hit in some environments.
      if (typeof value == 'string') {
        return value;
      }
      if (isArray(value)) {
        // Recursively convert values (susceptible to call stack limits).
        return arrayMap(value, baseToString) + '';
      }
      if (isSymbol(value)) {
        return symbolToString ? symbolToString.call(value) : '';
      }
      var result = (value + '');
      return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
    }

    /**
     * The base implementation of `_.uniqBy` without support for iteratee shorthands.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     */
    function baseUniq(array, iteratee, comparator) {
      var index = -1,
          includes = arrayIncludes,
          length = array.length,
          isCommon = true,
          result = [],
          seen = result;

      if (comparator) {
        isCommon = false;
        includes = arrayIncludesWith;
      }
      else if (length >= LARGE_ARRAY_SIZE) {
        var set = iteratee ? null : createSet(array);
        if (set) {
          return setToArray(set);
        }
        isCommon = false;
        includes = cacheHas;
        seen = new SetCache;
      }
      else {
        seen = iteratee ? [] : result;
      }
      outer:
      while (++index < length) {
        var value = array[index],
            computed = iteratee ? iteratee(value) : value;

        value = (comparator || value !== 0) ? value : 0;
        if (isCommon && computed === computed) {
          var seenIndex = seen.length;
          while (seenIndex--) {
            if (seen[seenIndex] === computed) {
              continue outer;
            }
          }
          if (iteratee) {
            seen.push(computed);
          }
          result.push(value);
        }
        else if (!includes(seen, computed, comparator)) {
          if (seen !== result) {
            seen.push(computed);
          }
          result.push(value);
        }
      }
      return result;
    }

    /**
     * The base implementation of `_.unset`.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {Array|string} path The property path to unset.
     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
     */
    function baseUnset(object, path) {
      path = castPath(path, object);
      object = parent(object, path);
      return object == null || delete object[toKey(last(path))];
    }

    /**
     * The base implementation of `_.update`.
     *
     * @private
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to update.
     * @param {Function} updater The function to produce the updated value.
     * @param {Function} [customizer] The function to customize path creation.
     * @returns {Object} Returns `object`.
     */
    function baseUpdate(object, path, updater, customizer) {
      return baseSet(object, path, updater(baseGet(object, path)), customizer);
    }

    /**
     * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
     * without support for iteratee shorthands.
     *
     * @private
     * @param {Array} array The array to query.
     * @param {Function} predicate The function invoked per iteration.
     * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Array} Returns the slice of `array`.
     */
    function baseWhile(array, predicate, isDrop, fromRight) {
      var length = array.length,
          index = fromRight ? length : -1;

      while ((fromRight ? index-- : ++index < length) &&
        predicate(array[index], index, array)) {}

      return isDrop
        ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
        : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
    }

    /**
     * The base implementation of `wrapperValue` which returns the result of
     * performing a sequence of actions on the unwrapped `value`, where each
     * successive action is supplied the return value of the previous.
     *
     * @private
     * @param {*} value The unwrapped value.
     * @param {Array} actions Actions to perform to resolve the unwrapped value.
     * @returns {*} Returns the resolved value.
     */
    function baseWrapperValue(value, actions) {
      var result = value;
      if (result instanceof LazyWrapper) {
        result = result.value();
      }
      return arrayReduce(actions, function(result, action) {
        return action.func.apply(action.thisArg, arrayPush([result], action.args));
      }, result);
    }

    /**
     * The base implementation of methods like `_.xor`, without support for
     * iteratee shorthands, that accepts an array of arrays to inspect.
     *
     * @private
     * @param {Array} arrays The arrays to inspect.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of values.
     */
    function baseXor(arrays, iteratee, comparator) {
      var length = arrays.length;
      if (length < 2) {
        return length ? baseUniq(arrays[0]) : [];
      }
      var index = -1,
          result = Array(length);

      while (++index < length) {
        var array = arrays[index],
            othIndex = -1;

        while (++othIndex < length) {
          if (othIndex != index) {
            result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
          }
        }
      }
      return baseUniq(baseFlatten(result, 1), iteratee, comparator);
    }

    /**
     * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
     *
     * @private
     * @param {Array} props The property identifiers.
     * @param {Array} values The property values.
     * @param {Function} assignFunc The function to assign values.
     * @returns {Object} Returns the new object.
     */
    function baseZipObject(props, values, assignFunc) {
      var index = -1,
          length = props.length,
          valsLength = values.length,
          result = {};

      while (++index < length) {
        var value = index < valsLength ? values[index] : undefined;
        assignFunc(result, props[index], value);
      }
      return result;
    }

    /**
     * Casts `value` to an empty array if it's not an array like object.
     *
     * @private
     * @param {*} value The value to inspect.
     * @returns {Array|Object} Returns the cast array-like object.
     */
    function castArrayLikeObject(value) {
      return isArrayLikeObject(value) ? value : [];
    }

    /**
     * Casts `value` to `identity` if it's not a function.
     *
     * @private
     * @param {*} value The value to inspect.
     * @returns {Function} Returns cast function.
     */
    function castFunction(value) {
      return typeof value == 'function' ? value : identity;
    }

    /**
     * Casts `value` to a path array if it's not one.
     *
     * @private
     * @param {*} value The value to inspect.
     * @param {Object} [object] The object to query keys on.
     * @returns {Array} Returns the cast property path array.
     */
    function castPath(value, object) {
      if (isArray(value)) {
        return value;
      }
      return isKey(value, object) ? [value] : stringToPath(toString(value));
    }

    /**
     * A `baseRest` alias which can be replaced with `identity` by module
     * replacement plugins.
     *
     * @private
     * @type {Function}
     * @param {Function} func The function to apply a rest parameter to.
     * @returns {Function} Returns the new function.
     */
    var castRest = baseRest;

    /**
     * Casts `array` to a slice if it's needed.
     *
     * @private
     * @param {Array} array The array to inspect.
     * @param {number} start The start position.
     * @param {number} [end=array.length] The end position.
     * @returns {Array} Returns the cast slice.
     */
    function castSlice(array, start, end) {
      var length = array.length;
      end = end === undefined ? length : end;
      return (!start && end >= length) ? array : baseSlice(array, start, end);
    }

    /**
     * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
     *
     * @private
     * @param {number|Object} id The timer id or timeout object of the timer to clear.
     */
    var clearTimeout = ctxClearTimeout || function(id) {
      return root.clearTimeout(id);
    };

    /**
     * Creates a clone of  `buffer`.
     *
     * @private
     * @param {Buffer} buffer The buffer to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Buffer} Returns the cloned buffer.
     */
    function cloneBuffer(buffer, isDeep) {
      if (isDeep) {
        return buffer.slice();
      }
      var length = buffer.length,
          result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);

      buffer.copy(result);
      return result;
    }

    /**
     * Creates a clone of `arrayBuffer`.
     *
     * @private
     * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
     * @returns {ArrayBuffer} Returns the cloned array buffer.
     */
    function cloneArrayBuffer(arrayBuffer) {
      var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
      new Uint8Array(result).set(new Uint8Array(arrayBuffer));
      return result;
    }

    /**
     * Creates a clone of `dataView`.
     *
     * @private
     * @param {Object} dataView The data view to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the cloned data view.
     */
    function cloneDataView(dataView, isDeep) {
      var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
      return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
    }

    /**
     * Creates a clone of `regexp`.
     *
     * @private
     * @param {Object} regexp The regexp to clone.
     * @returns {Object} Returns the cloned regexp.
     */
    function cloneRegExp(regexp) {
      var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
      result.lastIndex = regexp.lastIndex;
      return result;
    }

    /**
     * Creates a clone of the `symbol` object.
     *
     * @private
     * @param {Object} symbol The symbol object to clone.
     * @returns {Object} Returns the cloned symbol object.
     */
    function cloneSymbol(symbol) {
      return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
    }

    /**
     * Creates a clone of `typedArray`.
     *
     * @private
     * @param {Object} typedArray The typed array to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the cloned typed array.
     */
    function cloneTypedArray(typedArray, isDeep) {
      var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
      return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
    }

    /**
     * Compares values to sort them in ascending order.
     *
     * @private
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {number} Returns the sort order indicator for `value`.
     */
    function compareAscending(value, other) {
      if (value !== other) {
        var valIsDefined = value !== undefined,
            valIsNull = value === null,
            valIsReflexive = value === value,
            valIsSymbol = isSymbol(value);

        var othIsDefined = other !== undefined,
            othIsNull = other === null,
            othIsReflexive = other === other,
            othIsSymbol = isSymbol(other);

        if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
            (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
            (valIsNull && othIsDefined && othIsReflexive) ||
            (!valIsDefined && othIsReflexive) ||
            !valIsReflexive) {
          return 1;
        }
        if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
            (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
            (othIsNull && valIsDefined && valIsReflexive) ||
            (!othIsDefined && valIsReflexive) ||
            !othIsReflexive) {
          return -1;
        }
      }
      return 0;
    }

    /**
     * Used by `_.orderBy` to compare multiple properties of a value to another
     * and stable sort them.
     *
     * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
     * specify an order of "desc" for descending or "asc" for ascending sort order
     * of corresponding values.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {boolean[]|string[]} orders The order to sort by for each property.
     * @returns {number} Returns the sort order indicator for `object`.
     */
    function compareMultiple(object, other, orders) {
      var index = -1,
          objCriteria = object.criteria,
          othCriteria = other.criteria,
          length = objCriteria.length,
          ordersLength = orders.length;

      while (++index < length) {
        var result = compareAscending(objCriteria[index], othCriteria[index]);
        if (result) {
          if (index >= ordersLength) {
            return result;
          }
          var order = orders[index];
          return result * (order == 'desc' ? -1 : 1);
        }
      }
      // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
      // that causes it, under certain circumstances, to provide the same value for
      // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
      // for more details.
      //
      // This also ensures a stable sort in V8 and other engines.
      // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
      return object.index - other.index;
    }

    /**
     * Creates an array that is the composition of partially applied arguments,
     * placeholders, and provided arguments into a single array of arguments.
     *
     * @private
     * @param {Array} args The provided arguments.
     * @param {Array} partials The arguments to prepend to those provided.
     * @param {Array} holders The `partials` placeholder indexes.
     * @params {boolean} [isCurried] Specify composing for a curried function.
     * @returns {Array} Returns the new array of composed arguments.
     */
    function composeArgs(args, partials, holders, isCurried) {
      var argsIndex = -1,
          argsLength = args.length,
          holdersLength = holders.length,
          leftIndex = -1,
          leftLength = partials.length,
          rangeLength = nativeMax(argsLength - holdersLength, 0),
          result = Array(leftLength + rangeLength),
          isUncurried = !isCurried;

      while (++leftIndex < leftLength) {
        result[leftIndex] = partials[leftIndex];
      }
      while (++argsIndex < holdersLength) {
        if (isUncurried || argsIndex < argsLength) {
          result[holders[argsIndex]] = args[argsIndex];
        }
      }
      while (rangeLength--) {
        result[leftIndex++] = args[argsIndex++];
      }
      return result;
    }

    /**
     * This function is like `composeArgs` except that the arguments composition
     * is tailored for `_.partialRight`.
     *
     * @private
     * @param {Array} args The provided arguments.
     * @param {Array} partials The arguments to append to those provided.
     * @param {Array} holders The `partials` placeholder indexes.
     * @params {boolean} [isCurried] Specify composing for a curried function.
     * @returns {Array} Returns the new array of composed arguments.
     */
    function composeArgsRight(args, partials, holders, isCurried) {
      var argsIndex = -1,
          argsLength = args.length,
          holdersIndex = -1,
          holdersLength = holders.length,
          rightIndex = -1,
          rightLength = partials.length,
          rangeLength = nativeMax(argsLength - holdersLength, 0),
          result = Array(rangeLength + rightLength),
          isUncurried = !isCurried;

      while (++argsIndex < rangeLength) {
        result[argsIndex] = args[argsIndex];
      }
      var offset = argsIndex;
      while (++rightIndex < rightLength) {
        result[offset + rightIndex] = partials[rightIndex];
      }
      while (++holdersIndex < holdersLength) {
        if (isUncurried || argsIndex < argsLength) {
          result[offset + holders[holdersIndex]] = args[argsIndex++];
        }
      }
      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;
    }

    /**
     * Copies properties of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy properties from.
     * @param {Array} props The property identifiers to copy.
     * @param {Object} [object={}] The object to copy properties to.
     * @param {Function} [customizer] The function to customize copied values.
     * @returns {Object} Returns `object`.
     */
    function copyObject(source, props, object, customizer) {
      var isNew = !object;
      object || (object = {});

      var index = -1,
          length = props.length;

      while (++index < length) {
        var key = props[index];

        var newValue = customizer
          ? customizer(object[key], source[key], key, object, source)
          : undefined;

        if (newValue === undefined) {
          newValue = source[key];
        }
        if (isNew) {
          baseAssignValue(object, key, newValue);
        } else {
          assignValue(object, key, newValue);
        }
      }
      return object;
    }

    /**
     * Copies own symbols of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy symbols from.
     * @param {Object} [object={}] The object to copy symbols to.
     * @returns {Object} Returns `object`.
     */
    function copySymbols(source, object) {
      return copyObject(source, getSymbols(source), object);
    }

    /**
     * Copies own and inherited symbols of `source` to `object`.
     *
     * @private
     * @param {Object} source The object to copy symbols from.
     * @param {Object} [object={}] The object to copy symbols to.
     * @returns {Object} Returns `object`.
     */
    function copySymbolsIn(source, object) {
      return copyObject(source, getSymbolsIn(source), object);
    }

    /**
     * Creates a function like `_.groupBy`.
     *
     * @private
     * @param {Function} setter The function to set accumulator values.
     * @param {Function} [initializer] The accumulator object initializer.
     * @returns {Function} Returns the new aggregator function.
     */
    function createAggregator(setter, initializer) {
      return function(collection, iteratee) {
        var func = isArray(collection) ? arrayAggregator : baseAggregator,
            accumulator = initializer ? initializer() : {};

        return func(collection, setter, getIteratee(iteratee, 2), accumulator);
      };
    }

    /**
     * Creates a function like `_.assign`.
     *
     * @private
     * @param {Function} assigner The function to assign values.
     * @returns {Function} Returns the new assigner function.
     */
    function createAssigner(assigner) {
      return baseRest(function(object, sources) {
        var index = -1,
            length = sources.length,
            customizer = length > 1 ? sources[length - 1] : undefined,
            guard = length > 2 ? sources[2] : undefined;

        customizer = (assigner.length > 3 && typeof customizer == 'function')
          ? (length--, customizer)
          : undefined;

        if (guard && isIterateeCall(sources[0], sources[1], guard)) {
          customizer = length < 3 ? undefined : customizer;
          length = 1;
        }
        object = Object(object);
        while (++index < length) {
          var source = sources[index];
          if (source) {
            assigner(object, source, index, customizer);
          }
        }
        return object;
      });
    }

    /**
     * Creates a `baseEach` or `baseEachRight` function.
     *
     * @private
     * @param {Function} eachFunc The function to iterate over a collection.
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Function} Returns the new base function.
     */
    function createBaseEach(eachFunc, fromRight) {
      return function(collection, iteratee) {
        if (collection == null) {
          return collection;
        }
        if (!isArrayLike(collection)) {
          return eachFunc(collection, iteratee);
        }
        var length = collection.length,
            index = fromRight ? length : -1,
            iterable = Object(collection);

        while ((fromRight ? index-- : ++index < length)) {
          if (iteratee(iterable[index], index, iterable) === false) {
            break;
          }
        }
        return collection;
      };
    }

    /**
     * Creates a base function for methods like `_.forIn` and `_.forOwn`.
     *
     * @private
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Function} Returns the new base function.
     */
    function createBaseFor(fromRight) {
      return function(object, iteratee, keysFunc) {
        var index = -1,
            iterable = Object(object),
            props = keysFunc(object),
            length = props.length;

        while (length--) {
          var key = props[fromRight ? length : ++index];
          if (iteratee(iterable[key], key, iterable) === false) {
            break;
          }
        }
        return object;
      };
    }

    /**
     * Creates a function that wraps `func` to invoke it with the optional `this`
     * binding of `thisArg`.
     *
     * @private
     * @param {Function} func The function to wrap.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @param {*} [thisArg] The `this` binding of `func`.
     * @returns {Function} Returns the new wrapped function.
     */
    function createBind(func, bitmask, thisArg) {
      var isBind = bitmask & WRAP_BIND_FLAG,
          Ctor = createCtor(func);

      function wrapper() {
        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
        return fn.apply(isBind ? thisArg : this, arguments);
      }
      return wrapper;
    }

    /**
     * Creates a function like `_.lowerFirst`.
     *
     * @private
     * @param {string} methodName The name of the `String` case method to use.
     * @returns {Function} Returns the new case function.
     */
    function createCaseFirst(methodName) {
      return function(string) {
        string = toString(string);

        var strSymbols = hasUnicode(string)
          ? stringToArray(string)
          : undefined;

        var chr = strSymbols
          ? strSymbols[0]
          : string.charAt(0);

        var trailing = strSymbols
          ? castSlice(strSymbols, 1).join('')
          : string.slice(1);

        return chr[methodName]() + trailing;
      };
    }

    /**
     * Creates a function like `_.camelCase`.
     *
     * @private
     * @param {Function} callback The function to combine each word.
     * @returns {Function} Returns the new compounder function.
     */
    function createCompounder(callback) {
      return function(string) {
        return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
      };
    }

    /**
     * Creates a function that produces an instance of `Ctor` regardless of
     * whether it was invoked as part of a `new` expression or by `call` or `apply`.
     *
     * @private
     * @param {Function} Ctor The constructor to wrap.
     * @returns {Function} Returns the new wrapped function.
     */
    function createCtor(Ctor) {
      return function() {
        // Use a `switch` statement to work with class constructors. See
        // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
        // for more details.
        var args = arguments;
        switch (args.length) {
          case 0: return new Ctor;
          case 1: return new Ctor(args[0]);
          case 2: return new Ctor(args[0], args[1]);
          case 3: return new Ctor(args[0], args[1], args[2]);
          case 4: return new Ctor(args[0], args[1], args[2], args[3]);
          case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
          case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
          case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
        }
        var thisBinding = baseCreate(Ctor.prototype),
            result = Ctor.apply(thisBinding, args);

        // Mimic the constructor's `return` behavior.
        // See https://es5.github.io/#x13.2.2 for more details.
        return isObject(result) ? result : thisBinding;
      };
    }

    /**
     * Creates a function that wraps `func` to enable currying.
     *
     * @private
     * @param {Function} func The function to wrap.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @param {number} arity The arity of `func`.
     * @returns {Function} Returns the new wrapped function.
     */
    function createCurry(func, bitmask, arity) {
      var Ctor = createCtor(func);

      function wrapper() {
        var length = arguments.length,
            args = Array(length),
            index = length,
            placeholder = getHolder(wrapper);

        while (index--) {
          args[index] = arguments[index];
        }
        var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
          ? []
          : replaceHolders(args, placeholder);

        length -= holders.length;
        if (length < arity) {
          return createRecurry(
            func, bitmask, createHybrid, wrapper.placeholder, undefined,
            args, holders, undefined, undefined, arity - length);
        }
        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
        return apply(fn, this, args);
      }
      return wrapper;
    }

    /**
     * Creates a `_.find` or `_.findLast` function.
     *
     * @private
     * @param {Function} findIndexFunc The function to find the collection index.
     * @returns {Function} Returns the new find function.
     */
    function createFind(findIndexFunc) {
      return function(collection, predicate, fromIndex) {
        var iterable = Object(collection);
        if (!isArrayLike(collection)) {
          var iteratee = getIteratee(predicate, 3);
          collection = keys(collection);
          predicate = function(key) { return iteratee(iterable[key], key, iterable); };
        }
        var index = findIndexFunc(collection, predicate, fromIndex);
        return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
      };
    }

    /**
     * Creates a `_.flow` or `_.flowRight` function.
     *
     * @private
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Function} Returns the new flow function.
     */
    function createFlow(fromRight) {
      return flatRest(function(funcs) {
        var length = funcs.length,
            index = length,
            prereq = LodashWrapper.prototype.thru;

        if (fromRight) {
          funcs.reverse();
        }
        while (index--) {
          var func = funcs[index];
          if (typeof func != 'function') {
            throw new TypeError(FUNC_ERROR_TEXT);
          }
          if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
            var wrapper = new LodashWrapper([], true);
          }
        }
        index = wrapper ? index : length;
        while (++index < length) {
          func = funcs[index];

          var funcName = getFuncName(func),
              data = funcName == 'wrapper' ? getData(func) : undefined;

          if (data && isLaziable(data[0]) &&
                data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
                !data[4].length && data[9] == 1
              ) {
            wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
          } else {
            wrapper = (func.length == 1 && isLaziable(func))
              ? wrapper[funcName]()
              : wrapper.thru(func);
          }
        }
        return function() {
          var args = arguments,
              value = args[0];

          if (wrapper && args.length == 1 && isArray(value)) {
            return wrapper.plant(value).value();
          }
          var index = 0,
              result = length ? funcs[index].apply(this, args) : value;

          while (++index < length) {
            result = funcs[index].call(this, result);
          }
          return result;
        };
      });
    }

    /**
     * Creates a function that wraps `func` to invoke it with optional `this`
     * binding of `thisArg`, partial application, and currying.
     *
     * @private
     * @param {Function|string} func The function or method name to wrap.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @param {*} [thisArg] The `this` binding of `func`.
     * @param {Array} [partials] The arguments to prepend to those provided to
     *  the new function.
     * @param {Array} [holders] The `partials` placeholder indexes.
     * @param {Array} [partialsRight] The arguments to append to those provided
     *  to the new function.
     * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
     * @param {Array} [argPos] The argument positions of the new function.
     * @param {number} [ary] The arity cap of `func`.
     * @param {number} [arity] The arity of `func`.
     * @returns {Function} Returns the new wrapped function.
     */
    function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
      var isAry = bitmask & WRAP_ARY_FLAG,
          isBind = bitmask & WRAP_BIND_FLAG,
          isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
          isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
          isFlip = bitmask & WRAP_FLIP_FLAG,
          Ctor = isBindKey ? undefined : createCtor(func);

      function wrapper() {
        var length = arguments.length,
            args = Array(length),
            index = length;

        while (index--) {
          args[index] = arguments[index];
        }
        if (isCurried) {
          var placeholder = getHolder(wrapper),
              holdersCount = countHolders(args, placeholder);
        }
        if (partials) {
          args = composeArgs(args, partials, holders, isCurried);
        }
        if (partialsRight) {
          args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
        }
        length -= holdersCount;
        if (isCurried && length < arity) {
          var newHolders = replaceHolders(args, placeholder);
          return createRecurry(
            func, bitmask, createHybrid, wrapper.placeholder, thisArg,
            args, newHolders, argPos, ary, arity - length
          );
        }
        var thisBinding = isBind ? thisArg : this,
            fn = isBindKey ? thisBinding[func] : func;

        length = args.length;
        if (argPos) {
          args = reorder(args, argPos);
        } else if (isFlip && length > 1) {
          args.reverse();
        }
        if (isAry && ary < length) {
          args.length = ary;
        }
        if (this && this !== root && this instanceof wrapper) {
          fn = Ctor || createCtor(fn);
        }
        return fn.apply(thisBinding, args);
      }
      return wrapper;
    }

    /**
     * Creates a function like `_.invertBy`.
     *
     * @private
     * @param {Function} setter The function to set accumulator values.
     * @param {Function} toIteratee The function to resolve iteratees.
     * @returns {Function} Returns the new inverter function.
     */
    function createInverter(setter, toIteratee) {
      return function(object, iteratee) {
        return baseInverter(object, setter, toIteratee(iteratee), {});
      };
    }

    /**
     * Creates a function that performs a mathematical operation on two values.
     *
     * @private
     * @param {Function} operator The function to perform the operation.
     * @param {number} [defaultValue] The value used for `undefined` arguments.
     * @returns {Function} Returns the new mathematical operation function.
     */
    function createMathOperation(operator, defaultValue) {
      return function(value, other) {
        var result;
        if (value === undefined && other === undefined) {
          return defaultValue;
        }
        if (value !== undefined) {
          result = value;
        }
        if (other !== undefined) {
          if (result === undefined) {
            return other;
          }
          if (typeof value == 'string' || typeof other == 'string') {
            value = baseToString(value);
            other = baseToString(other);
          } else {
            value = baseToNumber(value);
            other = baseToNumber(other);
          }
          result = operator(value, other);
        }
        return result;
      };
    }

    /**
     * Creates a function like `_.over`.
     *
     * @private
     * @param {Function} arrayFunc The function to iterate over iteratees.
     * @returns {Function} Returns the new over function.
     */
    function createOver(arrayFunc) {
      return flatRest(function(iteratees) {
        iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
        return baseRest(function(args) {
          var thisArg = this;
          return arrayFunc(iteratees, function(iteratee) {
            return apply(iteratee, thisArg, args);
          });
        });
      });
    }

    /**
     * Creates the padding for `string` based on `length`. The `chars` string
     * is truncated if the number of characters exceeds `length`.
     *
     * @private
     * @param {number} length The padding length.
     * @param {string} [chars=' '] The string used as padding.
     * @returns {string} Returns the padding for `string`.
     */
    function createPadding(length, chars) {
      chars = chars === undefined ? ' ' : baseToString(chars);

      var charsLength = chars.length;
      if (charsLength < 2) {
        return charsLength ? baseRepeat(chars, length) : chars;
      }
      var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
      return hasUnicode(chars)
        ? castSlice(stringToArray(result), 0, length).join('')
        : result.slice(0, length);
    }

    /**
     * Creates a function that wraps `func` to invoke it with the `this` binding
     * of `thisArg` and `partials` prepended to the arguments it receives.
     *
     * @private
     * @param {Function} func The function to wrap.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @param {*} thisArg The `this` binding of `func`.
     * @param {Array} partials The arguments to prepend to those provided to
     *  the new function.
     * @returns {Function} Returns the new wrapped function.
     */
    function createPartial(func, bitmask, thisArg, partials) {
      var isBind = bitmask & WRAP_BIND_FLAG,
          Ctor = createCtor(func);

      function wrapper() {
        var argsIndex = -1,
            argsLength = arguments.length,
            leftIndex = -1,
            leftLength = partials.length,
            args = Array(leftLength + argsLength),
            fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;

        while (++leftIndex < leftLength) {
          args[leftIndex] = partials[leftIndex];
        }
        while (argsLength--) {
          args[leftIndex++] = arguments[++argsIndex];
        }
        return apply(fn, isBind ? thisArg : this, args);
      }
      return wrapper;
    }

    /**
     * Creates a `_.range` or `_.rangeRight` function.
     *
     * @private
     * @param {boolean} [fromRight] Specify iterating from right to left.
     * @returns {Function} Returns the new range function.
     */
    function createRange(fromRight) {
      return function(start, end, step) {
        if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
          end = step = undefined;
        }
        // Ensure the sign of `-0` is preserved.
        start = toFinite(start);
        if (end === undefined) {
          end = start;
          start = 0;
        } else {
          end = toFinite(end);
        }
        step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
        return baseRange(start, end, step, fromRight);
      };
    }

    /**
     * Creates a function that performs a relational operation on two values.
     *
     * @private
     * @param {Function} operator The function to perform the operation.
     * @returns {Function} Returns the new relational operation function.
     */
    function createRelationalOperation(operator) {
      return function(value, other) {
        if (!(typeof value == 'string' && typeof other == 'string')) {
          value = toNumber(value);
          other = toNumber(other);
        }
        return operator(value, other);
      };
    }

    /**
     * Creates a function that wraps `func` to continue currying.
     *
     * @private
     * @param {Function} func The function to wrap.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @param {Function} wrapFunc The function to create the `func` wrapper.
     * @param {*} placeholder The placeholder value.
     * @param {*} [thisArg] The `this` binding of `func`.
     * @param {Array} [partials] The arguments to prepend to those provided to
     *  the new function.
     * @param {Array} [holders] The `partials` placeholder indexes.
     * @param {Array} [argPos] The argument positions of the new function.
     * @param {number} [ary] The arity cap of `func`.
     * @param {number} [arity] The arity of `func`.
     * @returns {Function} Returns the new wrapped function.
     */
    function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
      var isCurry = bitmask & WRAP_CURRY_FLAG,
          newHolders = isCurry ? holders : undefined,
          newHoldersRight = isCurry ? undefined : holders,
          newPartials = isCurry ? partials : undefined,
          newPartialsRight = isCurry ? undefined : partials;

      bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
      bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);

      if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
        bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
      }
      var newData = [
        func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
        newHoldersRight, argPos, ary, arity
      ];

      var result = wrapFunc.apply(undefined, newData);
      if (isLaziable(func)) {
        setData(result, newData);
      }
      result.placeholder = placeholder;
      return setWrapToString(result, func, bitmask);
    }

    /**
     * Creates a function like `_.round`.
     *
     * @private
     * @param {string} methodName The name of the `Math` method to use when rounding.
     * @returns {Function} Returns the new round function.
     */
    function createRound(methodName) {
      var func = Math[methodName];
      return function(number, precision) {
        number = toNumber(number);
        precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
        if (precision && nativeIsFinite(number)) {
          // Shift with exponential notation to avoid floating-point issues.
          // See [MDN](https://mdn.io/round#Examples) for more details.
          var pair = (toString(number) + 'e').split('e'),
              value = func(pair[0] + 'e' + (+pair[1] + precision));

          pair = (toString(value) + 'e').split('e');
          return +(pair[0] + 'e' + (+pair[1] - precision));
        }
        return func(number);
      };
    }

    /**
     * Creates a set object of `values`.
     *
     * @private
     * @param {Array} values The values to add to the set.
     * @returns {Object} Returns the new set.
     */
    var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
      return new Set(values);
    };

    /**
     * Creates a `_.toPairs` or `_.toPairsIn` function.
     *
     * @private
     * @param {Function} keysFunc The function to get the keys of a given object.
     * @returns {Function} Returns the new pairs function.
     */
    function createToPairs(keysFunc) {
      return function(object) {
        var tag = getTag(object);
        if (tag == mapTag) {
          return mapToArray(object);
        }
        if (tag == setTag) {
          return setToPairs(object);
        }
        return baseToPairs(object, keysFunc(object));
      };
    }

    /**
     * Creates a function that either curries or invokes `func` with optional
     * `this` binding and partially applied arguments.
     *
     * @private
     * @param {Function|string} func The function or method name to wrap.
     * @param {number} bitmask The bitmask flags.
     *    1 - `_.bind`
     *    2 - `_.bindKey`
     *    4 - `_.curry` or `_.curryRight` of a bound function
     *    8 - `_.curry`
     *   16 - `_.curryRight`
     *   32 - `_.partial`
     *   64 - `_.partialRight`
     *  128 - `_.rearg`
     *  256 - `_.ary`
     *  512 - `_.flip`
     * @param {*} [thisArg] The `this` binding of `func`.
     * @param {Array} [partials] The arguments to be partially applied.
     * @param {Array} [holders] The `partials` placeholder indexes.
     * @param {Array} [argPos] The argument positions of the new function.
     * @param {number} [ary] The arity cap of `func`.
     * @param {number} [arity] The arity of `func`.
     * @returns {Function} Returns the new wrapped function.
     */
    function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
      var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
      if (!isBindKey && typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      var length = partials ? partials.length : 0;
      if (!length) {
        bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
        partials = holders = undefined;
      }
      ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
      arity = arity === undefined ? arity : toInteger(arity);
      length -= holders ? holders.length : 0;

      if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
        var partialsRight = partials,
            holdersRight = holders;

        partials = holders = undefined;
      }
      var data = isBindKey ? undefined : getData(func);

      var newData = [
        func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
        argPos, ary, arity
      ];

      if (data) {
        mergeData(newData, data);
      }
      func = newData[0];
      bitmask = newData[1];
      thisArg = newData[2];
      partials = newData[3];
      holders = newData[4];
      arity = newData[9] = newData[9] === undefined
        ? (isBindKey ? 0 : func.length)
        : nativeMax(newData[9] - length, 0);

      if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
        bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
      }
      if (!bitmask || bitmask == WRAP_BIND_FLAG) {
        var result = createBind(func, bitmask, thisArg);
      } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
        result = createCurry(func, bitmask, arity);
      } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
        result = createPartial(func, bitmask, thisArg, partials);
      } else {
        result = createHybrid.apply(undefined, newData);
      }
      var setter = data ? baseSetData : setData;
      return setWrapToString(setter(result, newData), func, bitmask);
    }

    /**
     * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
     * of source objects to the destination object for all destination properties
     * that resolve to `undefined`.
     *
     * @private
     * @param {*} objValue The destination value.
     * @param {*} srcValue The source value.
     * @param {string} key The key of the property to assign.
     * @param {Object} object The parent object of `objValue`.
     * @returns {*} Returns the value to assign.
     */
    function customDefaultsAssignIn(objValue, srcValue, key, object) {
      if (objValue === undefined ||
          (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
        return srcValue;
      }
      return objValue;
    }

    /**
     * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
     * objects into destination objects that are passed thru.
     *
     * @private
     * @param {*} objValue The destination value.
     * @param {*} srcValue The source value.
     * @param {string} key The key of the property to merge.
     * @param {Object} object The parent object of `objValue`.
     * @param {Object} source The parent object of `srcValue`.
     * @param {Object} [stack] Tracks traversed source values and their merged
     *  counterparts.
     * @returns {*} Returns the value to assign.
     */
    function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
      if (isObject(objValue) && isObject(srcValue)) {
        // Recursively merge objects and arrays (susceptible to call stack limits).
        stack.set(srcValue, objValue);
        baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
        stack['delete'](srcValue);
      }
      return objValue;
    }

    /**
     * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
     * objects.
     *
     * @private
     * @param {*} value The value to inspect.
     * @param {string} key The key of the property to inspect.
     * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
     */
    function customOmitClone(value) {
      return isPlainObject(value) ? undefined : value;
    }

    /**
     * A specialized version of `baseIsEqualDeep` for arrays with support for
     * partial deep comparisons.
     *
     * @private
     * @param {Array} array The array to compare.
     * @param {Array} other The other array to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `array` and `other` objects.
     * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
     */
    function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
      var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
          arrLength = array.length,
          othLength = other.length;

      if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
        return false;
      }
      // Check that cyclic values are equal.
      var arrStacked = stack.get(array);
      var othStacked = stack.get(other);
      if (arrStacked && othStacked) {
        return arrStacked == other && othStacked == array;
      }
      var index = -1,
          result = true,
          seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;

      stack.set(array, other);
      stack.set(other, array);

      // Ignore non-index properties.
      while (++index < arrLength) {
        var arrValue = array[index],
            othValue = other[index];

        if (customizer) {
          var compared = isPartial
            ? customizer(othValue, arrValue, index, other, array, stack)
            : customizer(arrValue, othValue, index, array, other, stack);
        }
        if (compared !== undefined) {
          if (compared) {
            continue;
          }
          result = false;
          break;
        }
        // Recursively compare arrays (susceptible to call stack limits).
        if (seen) {
          if (!arraySome(other, function(othValue, othIndex) {
                if (!cacheHas(seen, othIndex) &&
                    (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
                  return seen.push(othIndex);
                }
              })) {
            result = false;
            break;
          }
        } else if (!(
              arrValue === othValue ||
                equalFunc(arrValue, othValue, bitmask, customizer, stack)
            )) {
          result = false;
          break;
        }
      }
      stack['delete'](array);
      stack['delete'](other);
      return result;
    }

    /**
     * A specialized version of `baseIsEqualDeep` for comparing objects of
     * the same `toStringTag`.
     *
     * **Note:** This function only supports comparing values with tags of
     * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {string} tag The `toStringTag` of the objects to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */
    function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
      switch (tag) {
        case dataViewTag:
          if ((object.byteLength != other.byteLength) ||
              (object.byteOffset != other.byteOffset)) {
            return false;
          }
          object = object.buffer;
          other = other.buffer;

        case arrayBufferTag:
          if ((object.byteLength != other.byteLength) ||
              !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
            return false;
          }
          return true;

        case boolTag:
        case dateTag:
        case numberTag:
          // Coerce booleans to `1` or `0` and dates to milliseconds.
          // Invalid dates are coerced to `NaN`.
          return eq(+object, +other);

        case errorTag:
          return object.name == other.name && object.message == other.message;

        case regexpTag:
        case stringTag:
          // Coerce regexes to strings and treat strings, primitives and objects,
          // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
          // for more details.
          return object == (other + '');

        case mapTag:
          var convert = mapToArray;

        case setTag:
          var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
          convert || (convert = setToArray);

          if (object.size != other.size && !isPartial) {
            return false;
          }
          // Assume cyclic values are equal.
          var stacked = stack.get(object);
          if (stacked) {
            return stacked == other;
          }
          bitmask |= COMPARE_UNORDERED_FLAG;

          // Recursively compare objects (susceptible to call stack limits).
          stack.set(object, other);
          var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
          stack['delete'](object);
          return result;

        case symbolTag:
          if (symbolValueOf) {
            return symbolValueOf.call(object) == symbolValueOf.call(other);
          }
      }
      return false;
    }

    /**
     * A specialized version of `baseIsEqualDeep` for objects with support for
     * partial deep comparisons.
     *
     * @private
     * @param {Object} object The object to compare.
     * @param {Object} other The other object to compare.
     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
     * @param {Function} customizer The function to customize comparisons.
     * @param {Function} equalFunc The function to determine equivalents of values.
     * @param {Object} stack Tracks traversed `object` and `other` objects.
     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
     */
    function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
      var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
          objProps = getAllKeys(object),
          objLength = objProps.length,
          othProps = getAllKeys(other),
          othLength = othProps.length;

      if (objLength != othLength && !isPartial) {
        return false;
      }
      var index = objLength;
      while (index--) {
        var key = objProps[index];
        if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
          return false;
        }
      }
      // Check that cyclic values are equal.
      var objStacked = stack.get(object);
      var othStacked = stack.get(other);
      if (objStacked && othStacked) {
        return objStacked == other && othStacked == object;
      }
      var result = true;
      stack.set(object, other);
      stack.set(other, object);

      var skipCtor = isPartial;
      while (++index < objLength) {
        key = objProps[index];
        var objValue = object[key],
            othValue = other[key];

        if (customizer) {
          var compared = isPartial
            ? customizer(othValue, objValue, key, other, object, stack)
            : customizer(objValue, othValue, key, object, other, stack);
        }
        // Recursively compare objects (susceptible to call stack limits).
        if (!(compared === undefined
              ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
              : compared
            )) {
          result = false;
          break;
        }
        skipCtor || (skipCtor = key == 'constructor');
      }
      if (result && !skipCtor) {
        var objCtor = object.constructor,
            othCtor = other.constructor;

        // Non `Object` object instances with different constructors are not equal.
        if (objCtor != othCtor &&
            ('constructor' in object && 'constructor' in other) &&
            !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
              typeof othCtor == 'function' && othCtor instanceof othCtor)) {
          result = false;
        }
      }
      stack['delete'](object);
      stack['delete'](other);
      return result;
    }

    /**
     * A specialized version of `baseRest` which flattens the rest array.
     *
     * @private
     * @param {Function} func The function to apply a rest parameter to.
     * @returns {Function} Returns the new function.
     */
    function flatRest(func) {
      return setToString(overRest(func, undefined, flatten), func + '');
    }

    /**
     * Creates an array of own enumerable property names and symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names and symbols.
     */
    function getAllKeys(object) {
      return baseGetAllKeys(object, keys, getSymbols);
    }

    /**
     * Creates an array of own and inherited enumerable property names and
     * symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names and symbols.
     */
    function getAllKeysIn(object) {
      return baseGetAllKeys(object, keysIn, getSymbolsIn);
    }

    /**
     * Gets metadata for `func`.
     *
     * @private
     * @param {Function} func The function to query.
     * @returns {*} Returns the metadata for `func`.
     */
    var getData = !metaMap ? noop : function(func) {
      return metaMap.get(func);
    };

    /**
     * Gets the name of `func`.
     *
     * @private
     * @param {Function} func The function to query.
     * @returns {string} Returns the function name.
     */
    function getFuncName(func) {
      var result = (func.name + ''),
          array = realNames[result],
          length = hasOwnProperty.call(realNames, result) ? array.length : 0;

      while (length--) {
        var data = array[length],
            otherFunc = data.func;
        if (otherFunc == null || otherFunc == func) {
          return data.name;
        }
      }
      return result;
    }

    /**
     * Gets the argument placeholder value for `func`.
     *
     * @private
     * @param {Function} func The function to inspect.
     * @returns {*} Returns the placeholder value.
     */
    function getHolder(func) {
      var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
      return object.placeholder;
    }

    /**
     * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
     * this function returns the custom method, otherwise it returns `baseIteratee`.
     * If arguments are provided, the chosen function is invoked with them and
     * its result is returned.
     *
     * @private
     * @param {*} [value] The value to convert to an iteratee.
     * @param {number} [arity] The arity of the created iteratee.
     * @returns {Function} Returns the chosen function or its result.
     */
    function getIteratee() {
      var result = lodash.iteratee || iteratee;
      result = result === iteratee ? baseIteratee : result;
      return arguments.length ? result(arguments[0], arguments[1]) : result;
    }

    /**
     * Gets the data for `map`.
     *
     * @private
     * @param {Object} map The map to query.
     * @param {string} key The reference key.
     * @returns {*} Returns the map data.
     */
    function getMapData(map, key) {
      var data = map.__data__;
      return isKeyable(key)
        ? data[typeof key == 'string' ? 'string' : 'hash']
        : data.map;
    }

    /**
     * Gets the property names, values, and compare flags of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the match data of `object`.
     */
    function getMatchData(object) {
      var result = keys(object),
          length = result.length;

      while (length--) {
        var key = result[length],
            value = object[key];

        result[length] = [key, value, isStrictComparable(value)];
      }
      return result;
    }

    /**
     * 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;
    }

    /**
     * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
     *
     * @private
     * @param {*} value The value to query.
     * @returns {string} Returns the raw `toStringTag`.
     */
    function getRawTag(value) {
      var isOwn = hasOwnProperty.call(value, symToStringTag),
          tag = value[symToStringTag];

      try {
        value[symToStringTag] = undefined;
        var unmasked = true;
      } catch (e) {}

      var result = nativeObjectToString.call(value);
      if (unmasked) {
        if (isOwn) {
          value[symToStringTag] = tag;
        } else {
          delete value[symToStringTag];
        }
      }
      return result;
    }

    /**
     * Creates an array of the own enumerable symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of symbols.
     */
    var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
      if (object == null) {
        return [];
      }
      object = Object(object);
      return arrayFilter(nativeGetSymbols(object), function(symbol) {
        return propertyIsEnumerable.call(object, symbol);
      });
    };

    /**
     * Creates an array of the own and inherited enumerable symbols of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of symbols.
     */
    var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
      var result = [];
      while (object) {
        arrayPush(result, getSymbols(object));
        object = getPrototype(object);
      }
      return result;
    };

    /**
     * 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 and promises in Node.js < 6.
    if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
        (Map && getTag(new Map) != mapTag) ||
        (Promise && getTag(Promise.resolve()) != promiseTag) ||
        (Set && getTag(new Set) != setTag) ||
        (WeakMap && getTag(new WeakMap) != weakMapTag)) {
      getTag = function(value) {
        var result = baseGetTag(value),
            Ctor = result == objectTag ? value.constructor : undefined,
            ctorString = Ctor ? toSource(Ctor) : '';

        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;
      };
    }

    /**
     * Gets the view, applying any `transforms` to the `start` and `end` positions.
     *
     * @private
     * @param {number} start The start of the view.
     * @param {number} end The end of the view.
     * @param {Array} transforms The transformations to apply to the view.
     * @returns {Object} Returns an object containing the `start` and `end`
     *  positions of the view.
     */
    function getView(start, end, transforms) {
      var index = -1,
          length = transforms.length;

      while (++index < length) {
        var data = transforms[index],
            size = data.size;

        switch (data.type) {
          case 'drop':      start += size; break;
          case 'dropRight': end -= size; break;
          case 'take':      end = nativeMin(end, start + size); break;
          case 'takeRight': start = nativeMax(start, end - size); break;
        }
      }
      return { 'start': start, 'end': end };
    }

    /**
     * Extracts wrapper details from the `source` body comment.
     *
     * @private
     * @param {string} source The source to inspect.
     * @returns {Array} Returns the wrapper details.
     */
    function getWrapDetails(source) {
      var match = source.match(reWrapDetails);
      return match ? match[1].split(reSplitDetails) : [];
    }

    /**
     * Checks if `path` exists on `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Array|string} path The path to check.
     * @param {Function} hasFunc The function to check properties.
     * @returns {boolean} Returns `true` if `path` exists, else `false`.
     */
    function hasPath(object, path, hasFunc) {
      path = castPath(path, object);

      var index = -1,
          length = path.length,
          result = false;

      while (++index < length) {
        var key = toKey(path[index]);
        if (!(result = object != null && hasFunc(object, key))) {
          break;
        }
        object = object[key];
      }
      if (result || ++index != length) {
        return result;
      }
      length = object == null ? 0 : object.length;
      return !!length && isLength(length) && isIndex(key, length) &&
        (isArray(object) || isArguments(object));
    }

    /**
     * Initializes an array clone.
     *
     * @private
     * @param {Array} array The array to clone.
     * @returns {Array} Returns the initialized clone.
     */
    function initCloneArray(array) {
      var length = array.length,
          result = new array.constructor(length);

      // Add properties assigned by `RegExp#exec`.
      if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
        result.index = array.index;
        result.input = array.input;
      }
      return result;
    }

    /**
     * Initializes an object clone.
     *
     * @private
     * @param {Object} object The object to clone.
     * @returns {Object} Returns the initialized clone.
     */
    function initCloneObject(object) {
      return (typeof object.constructor == 'function' && !isPrototype(object))
        ? baseCreate(getPrototype(object))
        : {};
    }

    /**
     * Initializes an object clone based on its `toStringTag`.
     *
     * **Note:** This function only supports cloning values with tags of
     * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
     *
     * @private
     * @param {Object} object The object to clone.
     * @param {string} tag The `toStringTag` of the object to clone.
     * @param {boolean} [isDeep] Specify a deep clone.
     * @returns {Object} Returns the initialized clone.
     */
    function initCloneByTag(object, tag, isDeep) {
      var Ctor = object.constructor;
      switch (tag) {
        case arrayBufferTag:
          return cloneArrayBuffer(object);

        case boolTag:
        case dateTag:
          return new Ctor(+object);

        case dataViewTag:
          return cloneDataView(object, isDeep);

        case float32Tag: case float64Tag:
        case int8Tag: case int16Tag: case int32Tag:
        case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
          return cloneTypedArray(object, isDeep);

        case mapTag:
          return new Ctor;

        case numberTag:
        case stringTag:
          return new Ctor(object);

        case regexpTag:
          return cloneRegExp(object);

        case setTag:
          return new Ctor;

        case symbolTag:
          return cloneSymbol(object);
      }
    }

    /**
     * Inserts wrapper `details` in a comment at the top of the `source` body.
     *
     * @private
     * @param {string} source The source to modify.
     * @returns {Array} details The details to insert.
     * @returns {string} Returns the modified source.
     */
    function insertWrapDetails(source, details) {
      var length = details.length;
      if (!length) {
        return source;
      }
      var lastIndex = length - 1;
      details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
      details = details.join(length > 2 ? ', ' : ' ');
      return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
    }

    /**
     * Checks if `value` is a flattenable `arguments` object or array.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
     */
    function isFlattenable(value) {
      return isArray(value) || isArguments(value) ||
        !!(spreadableSymbol && value && value[spreadableSymbol]);
    }

    /**
     * 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) {
      var type = typeof value;
      length = length == null ? MAX_SAFE_INTEGER : length;

      return !!length &&
        (type == 'number' ||
          (type != 'symbol' && reIsUint.test(value))) &&
            (value > -1 && value % 1 == 0 && value < length);
    }

    /**
     * Checks if the given arguments are from an iteratee call.
     *
     * @private
     * @param {*} value The potential iteratee value argument.
     * @param {*} index The potential iteratee index or key argument.
     * @param {*} object The potential iteratee object argument.
     * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
     *  else `false`.
     */
    function isIterateeCall(value, index, object) {
      if (!isObject(object)) {
        return false;
      }
      var type = typeof index;
      if (type == 'number'
            ? (isArrayLike(object) && isIndex(index, object.length))
            : (type == 'string' && index in object)
          ) {
        return eq(object[index], value);
      }
      return false;
    }

    /**
     * Checks if `value` is a property name and not a property path.
     *
     * @private
     * @param {*} value The value to check.
     * @param {Object} [object] The object to query keys on.
     * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
     */
    function isKey(value, object) {
      if (isArray(value)) {
        return false;
      }
      var type = typeof value;
      if (type == 'number' || type == 'symbol' || type == 'boolean' ||
          value == null || isSymbol(value)) {
        return true;
      }
      return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
        (object != null && value in Object(object));
    }

    /**
     * Checks if `value` is suitable for use as unique object key.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
     */
    function isKeyable(value) {
      var type = typeof value;
      return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
        ? (value !== '__proto__')
        : (value === null);
    }

    /**
     * Checks if `func` has a lazy counterpart.
     *
     * @private
     * @param {Function} func The function to check.
     * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
     *  else `false`.
     */
    function isLaziable(func) {
      var funcName = getFuncName(func),
          other = lodash[funcName];

      if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
        return false;
      }
      if (func === other) {
        return true;
      }
      var data = getData(other);
      return !!data && func === data[0];
    }

    /**
     * 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 `func` is capable of being masked.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
     */
    var isMaskable = coreJsData ? isFunction : stubFalse;

    /**
     * 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;
    }

    /**
     * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
     *
     * @private
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` if suitable for strict
     *  equality comparisons, else `false`.
     */
    function isStrictComparable(value) {
      return value === value && !isObject(value);
    }

    /**
     * A specialized version of `matchesProperty` for source values suitable
     * for strict equality comparisons, i.e. `===`.
     *
     * @private
     * @param {string} key The key of the property to get.
     * @param {*} srcValue The value to match.
     * @returns {Function} Returns the new spec function.
     */
    function matchesStrictComparable(key, srcValue) {
      return function(object) {
        if (object == null) {
          return false;
        }
        return object[key] === srcValue &&
          (srcValue !== undefined || (key in Object(object)));
      };
    }

    /**
     * A specialized version of `_.memoize` which clears the memoized function's
     * cache when it exceeds `MAX_MEMOIZE_SIZE`.
     *
     * @private
     * @param {Function} func The function to have its output memoized.
     * @returns {Function} Returns the new memoized function.
     */
    function memoizeCapped(func) {
      var result = memoize(func, function(key) {
        if (cache.size === MAX_MEMOIZE_SIZE) {
          cache.clear();
        }
        return key;
      });

      var cache = result.cache;
      return result;
    }

    /**
     * Merges the function metadata of `source` into `data`.
     *
     * Merging metadata reduces the number of wrappers used to invoke a function.
     * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
     * may be applied regardless of execution order. Methods like `_.ary` and
     * `_.rearg` modify function arguments, making the order in which they are
     * executed important, preventing the merging of metadata. However, we make
     * an exception for a safe combined case where curried functions have `_.ary`
     * and or `_.rearg` applied.
     *
     * @private
     * @param {Array} data The destination metadata.
     * @param {Array} source The source metadata.
     * @returns {Array} Returns `data`.
     */
    function mergeData(data, source) {
      var bitmask = data[1],
          srcBitmask = source[1],
          newBitmask = bitmask | srcBitmask,
          isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);

      var isCombo =
        ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
        ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
        ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));

      // Exit early if metadata can't be merged.
      if (!(isCommon || isCombo)) {
        return data;
      }
      // Use source `thisArg` if available.
      if (srcBitmask & WRAP_BIND_FLAG) {
        data[2] = source[2];
        // Set when currying a bound function.
        newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
      }
      // Compose partial arguments.
      var value = source[3];
      if (value) {
        var partials = data[3];
        data[3] = partials ? composeArgs(partials, value, source[4]) : value;
        data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
      }
      // Compose partial right arguments.
      value = source[5];
      if (value) {
        partials = data[5];
        data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
        data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
      }
      // Use source `argPos` if available.
      value = source[7];
      if (value) {
        data[7] = value;
      }
      // Use source `ary` if it's smaller.
      if (srcBitmask & WRAP_ARY_FLAG) {
        data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
      }
      // Use source `arity` if one is not provided.
      if (data[9] == null) {
        data[9] = source[9];
      }
      // Use source `func` and merge bitmasks.
      data[0] = source[0];
      data[1] = newBitmask;

      return data;
    }

    /**
     * This function is like
     * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
     * except that it includes inherited enumerable properties.
     *
     * @private
     * @param {Object} object The object to query.
     * @returns {Array} Returns the array of property names.
     */
    function nativeKeysIn(object) {
      var result = [];
      if (object != null) {
        for (var key in Object(object)) {
          result.push(key);
        }
      }
      return result;
    }

    /**
     * Converts `value` to a string using `Object.prototype.toString`.
     *
     * @private
     * @param {*} value The value to convert.
     * @returns {string} Returns the converted string.
     */
    function objectToString(value) {
      return nativeObjectToString.call(value);
    }

    /**
     * A specialized version of `baseRest` which transforms the rest array.
     *
     * @private
     * @param {Function} func The function to apply a rest parameter to.
     * @param {number} [start=func.length-1] The start position of the rest parameter.
     * @param {Function} transform The rest array transform.
     * @returns {Function} Returns the new function.
     */
    function overRest(func, start, transform) {
      start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
      return function() {
        var args = arguments,
            index = -1,
            length = nativeMax(args.length - start, 0),
            array = Array(length);

        while (++index < length) {
          array[index] = args[start + index];
        }
        index = -1;
        var otherArgs = Array(start + 1);
        while (++index < start) {
          otherArgs[index] = args[index];
        }
        otherArgs[start] = transform(array);
        return apply(func, this, otherArgs);
      };
    }

    /**
     * Gets the parent value at `path` of `object`.
     *
     * @private
     * @param {Object} object The object to query.
     * @param {Array} path The path to get the parent value of.
     * @returns {*} Returns the parent value.
     */
    function parent(object, path) {
      return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
    }

    /**
     * Reorder `array` according to the specified indexes where the element at
     * the first index is assigned as the first element, the element at
     * the second index is assigned as the second element, and so on.
     *
     * @private
     * @param {Array} array The array to reorder.
     * @param {Array} indexes The arranged array indexes.
     * @returns {Array} Returns `array`.
     */
    function reorder(array, indexes) {
      var arrLength = array.length,
          length = nativeMin(indexes.length, arrLength),
          oldArray = copyArray(array);

      while (length--) {
        var index = indexes[length];
        array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
      }
      return array;
    }

    /**
     * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
     *
     * @private
     * @param {Object} object The object to query.
     * @param {string} key The key of the property to get.
     * @returns {*} Returns the property value.
     */
    function safeGet(object, key) {
      if (key === 'constructor' && typeof object[key] === 'function') {
        return;
      }

      if (key == '__proto__') {
        return;
      }

      return object[key];
    }

    /**
     * Sets metadata for `func`.
     *
     * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
     * period of time, it will trip its breaker and transition to an identity
     * function to avoid garbage collection pauses in V8. See
     * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
     * for more details.
     *
     * @private
     * @param {Function} func The function to associate metadata with.
     * @param {*} data The metadata.
     * @returns {Function} Returns `func`.
     */
    var setData = shortOut(baseSetData);

    /**
     * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
     *
     * @private
     * @param {Function} func The function to delay.
     * @param {number} wait The number of milliseconds to delay invocation.
     * @returns {number|Object} Returns the timer id or timeout object.
     */
    var setTimeout = ctxSetTimeout || function(func, wait) {
      return root.setTimeout(func, wait);
    };

    /**
     * Sets the `toString` method of `func` to return `string`.
     *
     * @private
     * @param {Function} func The function to modify.
     * @param {Function} string The `toString` result.
     * @returns {Function} Returns `func`.
     */
    var setToString = shortOut(baseSetToString);

    /**
     * Sets the `toString` method of `wrapper` to mimic the source of `reference`
     * with wrapper details in a comment at the top of the source body.
     *
     * @private
     * @param {Function} wrapper The function to modify.
     * @param {Function} reference The reference function.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @returns {Function} Returns `wrapper`.
     */
    function setWrapToString(wrapper, reference, bitmask) {
      var source = (reference + '');
      return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
    }

    /**
     * Creates a function that'll short out and invoke `identity` instead
     * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
     * milliseconds.
     *
     * @private
     * @param {Function} func The function to restrict.
     * @returns {Function} Returns the new shortable function.
     */
    function shortOut(func) {
      var count = 0,
          lastCalled = 0;

      return function() {
        var stamp = nativeNow(),
            remaining = HOT_SPAN - (stamp - lastCalled);

        lastCalled = stamp;
        if (remaining > 0) {
          if (++count >= HOT_COUNT) {
            return arguments[0];
          }
        } else {
          count = 0;
        }
        return func.apply(undefined, arguments);
      };
    }

    /**
     * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
     *
     * @private
     * @param {Array} array The array to shuffle.
     * @param {number} [size=array.length] The size of `array`.
     * @returns {Array} Returns `array`.
     */
    function shuffleSelf(array, size) {
      var index = -1,
          length = array.length,
          lastIndex = length - 1;

      size = size === undefined ? length : size;
      while (++index < size) {
        var rand = baseRandom(index, lastIndex),
            value = array[rand];

        array[rand] = array[index];
        array[index] = value;
      }
      array.length = size;
      return array;
    }

    /**
     * Converts `string` to a property path array.
     *
     * @private
     * @param {string} string The string to convert.
     * @returns {Array} Returns the property path array.
     */
    var stringToPath = memoizeCapped(function(string) {
      var result = [];
      if (string.charCodeAt(0) === 46 /* . */) {
        result.push('');
      }
      string.replace(rePropName, function(match, number, quote, subString) {
        result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
      });
      return result;
    });

    /**
     * Converts `value` to a string key if it's not a string or symbol.
     *
     * @private
     * @param {*} value The value to inspect.
     * @returns {string|symbol} Returns the key.
     */
    function toKey(value) {
      if (typeof value == 'string' || isSymbol(value)) {
        return value;
      }
      var result = (value + '');
      return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
    }

    /**
     * Converts `func` to its source code.
     *
     * @private
     * @param {Function} func The function to convert.
     * @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 '';
    }

    /**
     * Updates wrapper `details` based on `bitmask` flags.
     *
     * @private
     * @returns {Array} details The details to modify.
     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
     * @returns {Array} Returns `details`.
     */
    function updateWrapDetails(details, bitmask) {
      arrayEach(wrapFlags, function(pair) {
        var value = '_.' + pair[0];
        if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
          details.push(value);
        }
      });
      return details.sort();
    }

    /**
     * Creates a clone of `wrapper`.
     *
     * @private
     * @param {Object} wrapper The wrapper to clone.
     * @returns {Object} Returns the cloned wrapper.
     */
    function wrapperClone(wrapper) {
      if (wrapper instanceof LazyWrapper) {
        return wrapper.clone();
      }
      var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
      result.__actions__ = copyArray(wrapper.__actions__);
      result.__index__  = wrapper.__index__;
      result.__values__ = wrapper.__values__;
      return result;
    }

    /*------------------------------------------------------------------------*/

    /**
     * Creates an array of elements split into groups the length of `size`.
     * If `array` can't be split evenly, the final chunk will be the remaining
     * elements.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to process.
     * @param {number} [size=1] The length of each chunk
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the new array of chunks.
     * @example
     *
     * _.chunk(['a', 'b', 'c', 'd'], 2);
     * // => [['a', 'b'], ['c', 'd']]
     *
     * _.chunk(['a', 'b', 'c', 'd'], 3);
     * // => [['a', 'b', 'c'], ['d']]
     */
    function chunk(array, size, guard) {
      if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
        size = 1;
      } else {
        size = nativeMax(toInteger(size), 0);
      }
      var length = array == null ? 0 : array.length;
      if (!length || size < 1) {
        return [];
      }
      var index = 0,
          resIndex = 0,
          result = Array(nativeCeil(length / size));

      while (index < length) {
        result[resIndex++] = baseSlice(array, index, (index += size));
      }
      return result;
    }

    /**
     * Creates an array with all falsey values removed. The values `false`, `null`,
     * `0`, `""`, `undefined`, and `NaN` are falsey.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to compact.
     * @returns {Array} Returns the new array of filtered values.
     * @example
     *
     * _.compact([0, 1, false, 2, '', 3]);
     * // => [1, 2, 3]
     */
    function compact(array) {
      var index = -1,
          length = array == null ? 0 : array.length,
          resIndex = 0,
          result = [];

      while (++index < length) {
        var value = array[index];
        if (value) {
          result[resIndex++] = value;
        }
      }
      return result;
    }

    /**
     * Creates a new array concatenating `array` with any additional arrays
     * and/or values.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to concatenate.
     * @param {...*} [values] The values to concatenate.
     * @returns {Array} Returns the new concatenated array.
     * @example
     *
     * var array = [1];
     * var other = _.concat(array, 2, [3], [[4]]);
     *
     * console.log(other);
     * // => [1, 2, 3, [4]]
     *
     * console.log(array);
     * // => [1]
     */
    function concat() {
      var length = arguments.length;
      if (!length) {
        return [];
      }
      var args = Array(length - 1),
          array = arguments[0],
          index = length;

      while (index--) {
        args[index - 1] = arguments[index];
      }
      return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
    }

    /**
     * Creates an array of `array` values not included in the other given arrays
     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons. The order and references of result values are
     * determined by the first array.
     *
     * **Note:** Unlike `_.pullAll`, this method returns a new array.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {...Array} [values] The values to exclude.
     * @returns {Array} Returns the new array of filtered values.
     * @see _.without, _.xor
     * @example
     *
     * _.difference([2, 1], [2, 3]);
     * // => [1]
     */
    var difference = baseRest(function(array, values) {
      return isArrayLikeObject(array)
        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
        : [];
    });

    /**
     * This method is like `_.difference` except that it accepts `iteratee` which
     * is invoked for each element of `array` and `values` to generate the criterion
     * by which they're compared. The order and references of result values are
     * determined by the first array. The iteratee is invoked with one argument:
     * (value).
     *
     * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {...Array} [values] The values to exclude.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns the new array of filtered values.
     * @example
     *
     * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
     * // => [1.2]
     *
     * // The `_.property` iteratee shorthand.
     * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
     * // => [{ 'x': 2 }]
     */
    var differenceBy = baseRest(function(array, values) {
      var iteratee = last(values);
      if (isArrayLikeObject(iteratee)) {
        iteratee = undefined;
      }
      return isArrayLikeObject(array)
        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
        : [];
    });

    /**
     * This method is like `_.difference` except that it accepts `comparator`
     * which is invoked to compare elements of `array` to `values`. The order and
     * references of result values are determined by the first array. The comparator
     * is invoked with two arguments: (arrVal, othVal).
     *
     * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {...Array} [values] The values to exclude.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of filtered values.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
     *
     * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
     * // => [{ 'x': 2, 'y': 1 }]
     */
    var differenceWith = baseRest(function(array, values) {
      var comparator = last(values);
      if (isArrayLikeObject(comparator)) {
        comparator = undefined;
      }
      return isArrayLikeObject(array)
        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
        : [];
    });

    /**
     * Creates a slice of `array` with `n` elements dropped from the beginning.
     *
     * @static
     * @memberOf _
     * @since 0.5.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {number} [n=1] The number of elements to drop.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.drop([1, 2, 3]);
     * // => [2, 3]
     *
     * _.drop([1, 2, 3], 2);
     * // => [3]
     *
     * _.drop([1, 2, 3], 5);
     * // => []
     *
     * _.drop([1, 2, 3], 0);
     * // => [1, 2, 3]
     */
    function drop(array, n, guard) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      n = (guard || n === undefined) ? 1 : toInteger(n);
      return baseSlice(array, n < 0 ? 0 : n, length);
    }

    /**
     * Creates a slice of `array` with `n` elements dropped from the end.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {number} [n=1] The number of elements to drop.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.dropRight([1, 2, 3]);
     * // => [1, 2]
     *
     * _.dropRight([1, 2, 3], 2);
     * // => [1]
     *
     * _.dropRight([1, 2, 3], 5);
     * // => []
     *
     * _.dropRight([1, 2, 3], 0);
     * // => [1, 2, 3]
     */
    function dropRight(array, n, guard) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      n = (guard || n === undefined) ? 1 : toInteger(n);
      n = length - n;
      return baseSlice(array, 0, n < 0 ? 0 : n);
    }

    /**
     * Creates a slice of `array` excluding elements dropped from the end.
     * Elements are dropped until `predicate` returns falsey. The predicate is
     * invoked with three arguments: (value, index, array).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': true },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': false }
     * ];
     *
     * _.dropRightWhile(users, function(o) { return !o.active; });
     * // => objects for ['barney']
     *
     * // The `_.matches` iteratee shorthand.
     * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
     * // => objects for ['barney', 'fred']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.dropRightWhile(users, ['active', false]);
     * // => objects for ['barney']
     *
     * // The `_.property` iteratee shorthand.
     * _.dropRightWhile(users, 'active');
     * // => objects for ['barney', 'fred', 'pebbles']
     */
    function dropRightWhile(array, predicate) {
      return (array && array.length)
        ? baseWhile(array, getIteratee(predicate, 3), true, true)
        : [];
    }

    /**
     * Creates a slice of `array` excluding elements dropped from the beginning.
     * Elements are dropped until `predicate` returns falsey. The predicate is
     * invoked with three arguments: (value, index, array).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': false },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': true }
     * ];
     *
     * _.dropWhile(users, function(o) { return !o.active; });
     * // => objects for ['pebbles']
     *
     * // The `_.matches` iteratee shorthand.
     * _.dropWhile(users, { 'user': 'barney', 'active': false });
     * // => objects for ['fred', 'pebbles']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.dropWhile(users, ['active', false]);
     * // => objects for ['pebbles']
     *
     * // The `_.property` iteratee shorthand.
     * _.dropWhile(users, 'active');
     * // => objects for ['barney', 'fred', 'pebbles']
     */
    function dropWhile(array, predicate) {
      return (array && array.length)
        ? baseWhile(array, getIteratee(predicate, 3), true)
        : [];
    }

    /**
     * Fills elements of `array` with `value` from `start` up to, but not
     * including, `end`.
     *
     * **Note:** This method mutates `array`.
     *
     * @static
     * @memberOf _
     * @since 3.2.0
     * @category Array
     * @param {Array} array The array to fill.
     * @param {*} value The value to fill `array` with.
     * @param {number} [start=0] The start position.
     * @param {number} [end=array.length] The end position.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = [1, 2, 3];
     *
     * _.fill(array, 'a');
     * console.log(array);
     * // => ['a', 'a', 'a']
     *
     * _.fill(Array(3), 2);
     * // => [2, 2, 2]
     *
     * _.fill([4, 6, 8, 10], '*', 1, 3);
     * // => [4, '*', '*', 10]
     */
    function fill(array, value, start, end) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
        start = 0;
        end = length;
      }
      return baseFill(array, value, start, end);
    }

    /**
     * This method is like `_.find` except that it returns the index of the first
     * element `predicate` returns truthy for instead of the element itself.
     *
     * @static
     * @memberOf _
     * @since 1.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param {number} [fromIndex=0] The index to search from.
     * @returns {number} Returns the index of the found element, else `-1`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': false },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': true }
     * ];
     *
     * _.findIndex(users, function(o) { return o.user == 'barney'; });
     * // => 0
     *
     * // The `_.matches` iteratee shorthand.
     * _.findIndex(users, { 'user': 'fred', 'active': false });
     * // => 1
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.findIndex(users, ['active', false]);
     * // => 0
     *
     * // The `_.property` iteratee shorthand.
     * _.findIndex(users, 'active');
     * // => 2
     */
    function findIndex(array, predicate, fromIndex) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return -1;
      }
      var index = fromIndex == null ? 0 : toInteger(fromIndex);
      if (index < 0) {
        index = nativeMax(length + index, 0);
      }
      return baseFindIndex(array, getIteratee(predicate, 3), index);
    }

    /**
     * This method is like `_.findIndex` except that it iterates over elements
     * of `collection` from right to left.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param {number} [fromIndex=array.length-1] The index to search from.
     * @returns {number} Returns the index of the found element, else `-1`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': true },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': false }
     * ];
     *
     * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
     * // => 2
     *
     * // The `_.matches` iteratee shorthand.
     * _.findLastIndex(users, { 'user': 'barney', 'active': true });
     * // => 0
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.findLastIndex(users, ['active', false]);
     * // => 2
     *
     * // The `_.property` iteratee shorthand.
     * _.findLastIndex(users, 'active');
     * // => 0
     */
    function findLastIndex(array, predicate, fromIndex) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return -1;
      }
      var index = length - 1;
      if (fromIndex !== undefined) {
        index = toInteger(fromIndex);
        index = fromIndex < 0
          ? nativeMax(length + index, 0)
          : nativeMin(index, length - 1);
      }
      return baseFindIndex(array, getIteratee(predicate, 3), index, true);
    }

    /**
     * Flattens `array` a single level deep.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to flatten.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * _.flatten([1, [2, [3, [4]], 5]]);
     * // => [1, 2, [3, [4]], 5]
     */
    function flatten(array) {
      var length = array == null ? 0 : array.length;
      return length ? baseFlatten(array, 1) : [];
    }

    /**
     * Recursively flattens `array`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to flatten.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * _.flattenDeep([1, [2, [3, [4]], 5]]);
     * // => [1, 2, 3, 4, 5]
     */
    function flattenDeep(array) {
      var length = array == null ? 0 : array.length;
      return length ? baseFlatten(array, INFINITY) : [];
    }

    /**
     * Recursively flatten `array` up to `depth` times.
     *
     * @static
     * @memberOf _
     * @since 4.4.0
     * @category Array
     * @param {Array} array The array to flatten.
     * @param {number} [depth=1] The maximum recursion depth.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * var array = [1, [2, [3, [4]], 5]];
     *
     * _.flattenDepth(array, 1);
     * // => [1, 2, [3, [4]], 5]
     *
     * _.flattenDepth(array, 2);
     * // => [1, 2, 3, [4], 5]
     */
    function flattenDepth(array, depth) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      depth = depth === undefined ? 1 : toInteger(depth);
      return baseFlatten(array, depth);
    }

    /**
     * The inverse of `_.toPairs`; this method returns an object composed
     * from key-value `pairs`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} pairs The key-value pairs.
     * @returns {Object} Returns the new object.
     * @example
     *
     * _.fromPairs([['a', 1], ['b', 2]]);
     * // => { 'a': 1, 'b': 2 }
     */
    function fromPairs(pairs) {
      var index = -1,
          length = pairs == null ? 0 : pairs.length,
          result = {};

      while (++index < length) {
        var pair = pairs[index];
        result[pair[0]] = pair[1];
      }
      return result;
    }

    /**
     * Gets the first element of `array`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @alias first
     * @category Array
     * @param {Array} array The array to query.
     * @returns {*} Returns the first element of `array`.
     * @example
     *
     * _.head([1, 2, 3]);
     * // => 1
     *
     * _.head([]);
     * // => undefined
     */
    function head(array) {
      return (array && array.length) ? array[0] : undefined;
    }

    /**
     * Gets the index at which the first occurrence of `value` is found in `array`
     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons. If `fromIndex` is negative, it's used as the
     * offset from the end of `array`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {*} value The value to search for.
     * @param {number} [fromIndex=0] The index to search from.
     * @returns {number} Returns the index of the matched value, else `-1`.
     * @example
     *
     * _.indexOf([1, 2, 1, 2], 2);
     * // => 1
     *
     * // Search from the `fromIndex`.
     * _.indexOf([1, 2, 1, 2], 2, 2);
     * // => 3
     */
    function indexOf(array, value, fromIndex) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return -1;
      }
      var index = fromIndex == null ? 0 : toInteger(fromIndex);
      if (index < 0) {
        index = nativeMax(length + index, 0);
      }
      return baseIndexOf(array, value, index);
    }

    /**
     * Gets all but the last element of `array`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to query.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.initial([1, 2, 3]);
     * // => [1, 2]
     */
    function initial(array) {
      var length = array == null ? 0 : array.length;
      return length ? baseSlice(array, 0, -1) : [];
    }

    /**
     * Creates an array of unique values that are included in all given arrays
     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons. The order and references of result values are
     * determined by the first array.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @returns {Array} Returns the new array of intersecting values.
     * @example
     *
     * _.intersection([2, 1], [2, 3]);
     * // => [2]
     */
    var intersection = baseRest(function(arrays) {
      var mapped = arrayMap(arrays, castArrayLikeObject);
      return (mapped.length && mapped[0] === arrays[0])
        ? baseIntersection(mapped)
        : [];
    });

    /**
     * This method is like `_.intersection` except that it accepts `iteratee`
     * which is invoked for each element of each `arrays` to generate the criterion
     * by which they're compared. The order and references of result values are
     * determined by the first array. The iteratee is invoked with one argument:
     * (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns the new array of intersecting values.
     * @example
     *
     * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
     * // => [2.1]
     *
     * // The `_.property` iteratee shorthand.
     * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
     * // => [{ 'x': 1 }]
     */
    var intersectionBy = baseRest(function(arrays) {
      var iteratee = last(arrays),
          mapped = arrayMap(arrays, castArrayLikeObject);

      if (iteratee === last(mapped)) {
        iteratee = undefined;
      } else {
        mapped.pop();
      }
      return (mapped.length && mapped[0] === arrays[0])
        ? baseIntersection(mapped, getIteratee(iteratee, 2))
        : [];
    });

    /**
     * This method is like `_.intersection` except that it accepts `comparator`
     * which is invoked to compare elements of `arrays`. The order and references
     * of result values are determined by the first array. The comparator is
     * invoked with two arguments: (arrVal, othVal).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of intersecting values.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
     *
     * _.intersectionWith(objects, others, _.isEqual);
     * // => [{ 'x': 1, 'y': 2 }]
     */
    var intersectionWith = baseRest(function(arrays) {
      var comparator = last(arrays),
          mapped = arrayMap(arrays, castArrayLikeObject);

      comparator = typeof comparator == 'function' ? comparator : undefined;
      if (comparator) {
        mapped.pop();
      }
      return (mapped.length && mapped[0] === arrays[0])
        ? baseIntersection(mapped, undefined, comparator)
        : [];
    });

    /**
     * Converts all elements in `array` into a string separated by `separator`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to convert.
     * @param {string} [separator=','] The element separator.
     * @returns {string} Returns the joined string.
     * @example
     *
     * _.join(['a', 'b', 'c'], '~');
     * // => 'a~b~c'
     */
    function join(array, separator) {
      return array == null ? '' : nativeJoin.call(array, separator);
    }

    /**
     * Gets the last element of `array`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to query.
     * @returns {*} Returns the last element of `array`.
     * @example
     *
     * _.last([1, 2, 3]);
     * // => 3
     */
    function last(array) {
      var length = array == null ? 0 : array.length;
      return length ? array[length - 1] : undefined;
    }

    /**
     * This method is like `_.indexOf` except that it iterates over elements of
     * `array` from right to left.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {*} value The value to search for.
     * @param {number} [fromIndex=array.length-1] The index to search from.
     * @returns {number} Returns the index of the matched value, else `-1`.
     * @example
     *
     * _.lastIndexOf([1, 2, 1, 2], 2);
     * // => 3
     *
     * // Search from the `fromIndex`.
     * _.lastIndexOf([1, 2, 1, 2], 2, 2);
     * // => 1
     */
    function lastIndexOf(array, value, fromIndex) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return -1;
      }
      var index = length;
      if (fromIndex !== undefined) {
        index = toInteger(fromIndex);
        index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
      }
      return value === value
        ? strictLastIndexOf(array, value, index)
        : baseFindIndex(array, baseIsNaN, index, true);
    }

    /**
     * Gets the element at index `n` of `array`. If `n` is negative, the nth
     * element from the end is returned.
     *
     * @static
     * @memberOf _
     * @since 4.11.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {number} [n=0] The index of the element to return.
     * @returns {*} Returns the nth element of `array`.
     * @example
     *
     * var array = ['a', 'b', 'c', 'd'];
     *
     * _.nth(array, 1);
     * // => 'b'
     *
     * _.nth(array, -2);
     * // => 'c';
     */
    function nth(array, n) {
      return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
    }

    /**
     * Removes all given values from `array` using
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
     * to remove elements from an array by predicate.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {...*} [values] The values to remove.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
     *
     * _.pull(array, 'a', 'c');
     * console.log(array);
     * // => ['b', 'b']
     */
    var pull = baseRest(pullAll);

    /**
     * This method is like `_.pull` except that it accepts an array of values to remove.
     *
     * **Note:** Unlike `_.difference`, this method mutates `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {Array} values The values to remove.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
     *
     * _.pullAll(array, ['a', 'c']);
     * console.log(array);
     * // => ['b', 'b']
     */
    function pullAll(array, values) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values)
        : array;
    }

    /**
     * This method is like `_.pullAll` except that it accepts `iteratee` which is
     * invoked for each element of `array` and `values` to generate the criterion
     * by which they're compared. The iteratee is invoked with one argument: (value).
     *
     * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {Array} values The values to remove.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
     *
     * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
     * console.log(array);
     * // => [{ 'x': 2 }]
     */
    function pullAllBy(array, values, iteratee) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values, getIteratee(iteratee, 2))
        : array;
    }

    /**
     * This method is like `_.pullAll` except that it accepts `comparator` which
     * is invoked to compare elements of `array` to `values`. The comparator is
     * invoked with two arguments: (arrVal, othVal).
     *
     * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
     *
     * @static
     * @memberOf _
     * @since 4.6.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {Array} values The values to remove.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
     *
     * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
     * console.log(array);
     * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
     */
    function pullAllWith(array, values, comparator) {
      return (array && array.length && values && values.length)
        ? basePullAll(array, values, undefined, comparator)
        : array;
    }

    /**
     * Removes elements from `array` corresponding to `indexes` and returns an
     * array of removed elements.
     *
     * **Note:** Unlike `_.at`, this method mutates `array`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {...(number|number[])} [indexes] The indexes of elements to remove.
     * @returns {Array} Returns the new array of removed elements.
     * @example
     *
     * var array = ['a', 'b', 'c', 'd'];
     * var pulled = _.pullAt(array, [1, 3]);
     *
     * console.log(array);
     * // => ['a', 'c']
     *
     * console.log(pulled);
     * // => ['b', 'd']
     */
    var pullAt = flatRest(function(array, indexes) {
      var length = array == null ? 0 : array.length,
          result = baseAt(array, indexes);

      basePullAt(array, arrayMap(indexes, function(index) {
        return isIndex(index, length) ? +index : index;
      }).sort(compareAscending));

      return result;
    });

    /**
     * Removes all elements from `array` that `predicate` returns truthy for
     * and returns an array of the removed elements. The predicate is invoked
     * with three arguments: (value, index, array).
     *
     * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
     * to pull elements from an array by value.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new array of removed elements.
     * @example
     *
     * var array = [1, 2, 3, 4];
     * var evens = _.remove(array, function(n) {
     *   return n % 2 == 0;
     * });
     *
     * console.log(array);
     * // => [1, 3]
     *
     * console.log(evens);
     * // => [2, 4]
     */
    function remove(array, predicate) {
      var result = [];
      if (!(array && array.length)) {
        return result;
      }
      var index = -1,
          indexes = [],
          length = array.length;

      predicate = getIteratee(predicate, 3);
      while (++index < length) {
        var value = array[index];
        if (predicate(value, index, array)) {
          result.push(value);
          indexes.push(index);
        }
      }
      basePullAt(array, indexes);
      return result;
    }

    /**
     * Reverses `array` so that the first element becomes the last, the second
     * element becomes the second to last, and so on.
     *
     * **Note:** This method mutates `array` and is based on
     * [`Array#reverse`](https://mdn.io/Array/reverse).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to modify.
     * @returns {Array} Returns `array`.
     * @example
     *
     * var array = [1, 2, 3];
     *
     * _.reverse(array);
     * // => [3, 2, 1]
     *
     * console.log(array);
     * // => [3, 2, 1]
     */
    function reverse(array) {
      return array == null ? array : nativeReverse.call(array);
    }

    /**
     * Creates a slice of `array` from `start` up to, but not including, `end`.
     *
     * **Note:** This method is used instead of
     * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
     * returned.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to slice.
     * @param {number} [start=0] The start position.
     * @param {number} [end=array.length] The end position.
     * @returns {Array} Returns the slice of `array`.
     */
    function slice(array, start, end) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
        start = 0;
        end = length;
      }
      else {
        start = start == null ? 0 : toInteger(start);
        end = end === undefined ? length : toInteger(end);
      }
      return baseSlice(array, start, end);
    }

    /**
     * Uses a binary search to determine the lowest index at which `value`
     * should be inserted into `array` in order to maintain its sort order.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     * @example
     *
     * _.sortedIndex([30, 50], 40);
     * // => 1
     */
    function sortedIndex(array, value) {
      return baseSortedIndex(array, value);
    }

    /**
     * This method is like `_.sortedIndex` except that it accepts `iteratee`
     * which is invoked for `value` and each element of `array` to compute their
     * sort ranking. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     * @example
     *
     * var objects = [{ 'x': 4 }, { 'x': 5 }];
     *
     * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
     * // => 0
     *
     * // The `_.property` iteratee shorthand.
     * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
     * // => 0
     */
    function sortedIndexBy(array, value, iteratee) {
      return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
    }

    /**
     * This method is like `_.indexOf` except that it performs a binary
     * search on a sorted `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {*} value The value to search for.
     * @returns {number} Returns the index of the matched value, else `-1`.
     * @example
     *
     * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
     * // => 1
     */
    function sortedIndexOf(array, value) {
      var length = array == null ? 0 : array.length;
      if (length) {
        var index = baseSortedIndex(array, value);
        if (index < length && eq(array[index], value)) {
          return index;
        }
      }
      return -1;
    }

    /**
     * This method is like `_.sortedIndex` except that it returns the highest
     * index at which `value` should be inserted into `array` in order to
     * maintain its sort order.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     * @example
     *
     * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
     * // => 4
     */
    function sortedLastIndex(array, value) {
      return baseSortedIndex(array, value, true);
    }

    /**
     * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
     * which is invoked for `value` and each element of `array` to compute their
     * sort ranking. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The sorted array to inspect.
     * @param {*} value The value to evaluate.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {number} Returns the index at which `value` should be inserted
     *  into `array`.
     * @example
     *
     * var objects = [{ 'x': 4 }, { 'x': 5 }];
     *
     * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
     * // => 1
     *
     * // The `_.property` iteratee shorthand.
     * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
     * // => 1
     */
    function sortedLastIndexBy(array, value, iteratee) {
      return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
    }

    /**
     * This method is like `_.lastIndexOf` except that it performs a binary
     * search on a sorted `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {*} value The value to search for.
     * @returns {number} Returns the index of the matched value, else `-1`.
     * @example
     *
     * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
     * // => 3
     */
    function sortedLastIndexOf(array, value) {
      var length = array == null ? 0 : array.length;
      if (length) {
        var index = baseSortedIndex(array, value, true) - 1;
        if (eq(array[index], value)) {
          return index;
        }
      }
      return -1;
    }

    /**
     * This method is like `_.uniq` except that it's designed and optimized
     * for sorted arrays.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * _.sortedUniq([1, 1, 2]);
     * // => [1, 2]
     */
    function sortedUniq(array) {
      return (array && array.length)
        ? baseSortedUniq(array)
        : [];
    }

    /**
     * This method is like `_.uniqBy` except that it's designed and optimized
     * for sorted arrays.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Function} [iteratee] The iteratee invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
     * // => [1.1, 2.3]
     */
    function sortedUniqBy(array, iteratee) {
      return (array && array.length)
        ? baseSortedUniq(array, getIteratee(iteratee, 2))
        : [];
    }

    /**
     * Gets all but the first element of `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.tail([1, 2, 3]);
     * // => [2, 3]
     */
    function tail(array) {
      var length = array == null ? 0 : array.length;
      return length ? baseSlice(array, 1, length) : [];
    }

    /**
     * Creates a slice of `array` with `n` elements taken from the beginning.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {number} [n=1] The number of elements to take.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.take([1, 2, 3]);
     * // => [1]
     *
     * _.take([1, 2, 3], 2);
     * // => [1, 2]
     *
     * _.take([1, 2, 3], 5);
     * // => [1, 2, 3]
     *
     * _.take([1, 2, 3], 0);
     * // => []
     */
    function take(array, n, guard) {
      if (!(array && array.length)) {
        return [];
      }
      n = (guard || n === undefined) ? 1 : toInteger(n);
      return baseSlice(array, 0, n < 0 ? 0 : n);
    }

    /**
     * Creates a slice of `array` with `n` elements taken from the end.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {number} [n=1] The number of elements to take.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * _.takeRight([1, 2, 3]);
     * // => [3]
     *
     * _.takeRight([1, 2, 3], 2);
     * // => [2, 3]
     *
     * _.takeRight([1, 2, 3], 5);
     * // => [1, 2, 3]
     *
     * _.takeRight([1, 2, 3], 0);
     * // => []
     */
    function takeRight(array, n, guard) {
      var length = array == null ? 0 : array.length;
      if (!length) {
        return [];
      }
      n = (guard || n === undefined) ? 1 : toInteger(n);
      n = length - n;
      return baseSlice(array, n < 0 ? 0 : n, length);
    }

    /**
     * Creates a slice of `array` with elements taken from the end. Elements are
     * taken until `predicate` returns falsey. The predicate is invoked with
     * three arguments: (value, index, array).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': true },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': false }
     * ];
     *
     * _.takeRightWhile(users, function(o) { return !o.active; });
     * // => objects for ['fred', 'pebbles']
     *
     * // The `_.matches` iteratee shorthand.
     * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
     * // => objects for ['pebbles']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.takeRightWhile(users, ['active', false]);
     * // => objects for ['fred', 'pebbles']
     *
     * // The `_.property` iteratee shorthand.
     * _.takeRightWhile(users, 'active');
     * // => []
     */
    function takeRightWhile(array, predicate) {
      return (array && array.length)
        ? baseWhile(array, getIteratee(predicate, 3), false, true)
        : [];
    }

    /**
     * Creates a slice of `array` with elements taken from the beginning. Elements
     * are taken until `predicate` returns falsey. The predicate is invoked with
     * three arguments: (value, index, array).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Array
     * @param {Array} array The array to query.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the slice of `array`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'active': false },
     *   { 'user': 'fred',    'active': false },
     *   { 'user': 'pebbles', 'active': true }
     * ];
     *
     * _.takeWhile(users, function(o) { return !o.active; });
     * // => objects for ['barney', 'fred']
     *
     * // The `_.matches` iteratee shorthand.
     * _.takeWhile(users, { 'user': 'barney', 'active': false });
     * // => objects for ['barney']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.takeWhile(users, ['active', false]);
     * // => objects for ['barney', 'fred']
     *
     * // The `_.property` iteratee shorthand.
     * _.takeWhile(users, 'active');
     * // => []
     */
    function takeWhile(array, predicate) {
      return (array && array.length)
        ? baseWhile(array, getIteratee(predicate, 3))
        : [];
    }

    /**
     * Creates an array of unique values, in order, from all given arrays using
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @returns {Array} Returns the new array of combined values.
     * @example
     *
     * _.union([2], [1, 2]);
     * // => [2, 1]
     */
    var union = baseRest(function(arrays) {
      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
    });

    /**
     * This method is like `_.union` except that it accepts `iteratee` which is
     * invoked for each element of each `arrays` to generate the criterion by
     * which uniqueness is computed. Result values are chosen from the first
     * array in which the value occurs. The iteratee is invoked with one argument:
     * (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns the new array of combined values.
     * @example
     *
     * _.unionBy([2.1], [1.2, 2.3], Math.floor);
     * // => [2.1, 1.2]
     *
     * // The `_.property` iteratee shorthand.
     * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
     * // => [{ 'x': 1 }, { 'x': 2 }]
     */
    var unionBy = baseRest(function(arrays) {
      var iteratee = last(arrays);
      if (isArrayLikeObject(iteratee)) {
        iteratee = undefined;
      }
      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
    });

    /**
     * This method is like `_.union` except that it accepts `comparator` which
     * is invoked to compare elements of `arrays`. Result values are chosen from
     * the first array in which the value occurs. The comparator is invoked
     * with two arguments: (arrVal, othVal).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of combined values.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
     *
     * _.unionWith(objects, others, _.isEqual);
     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
     */
    var unionWith = baseRest(function(arrays) {
      var comparator = last(arrays);
      comparator = typeof comparator == 'function' ? comparator : undefined;
      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
    });

    /**
     * Creates a duplicate-free version of an array, using
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons, in which only the first occurrence of each element
     * is kept. The order of result values is determined by the order they occur
     * in the array.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * _.uniq([2, 1, 2]);
     * // => [2, 1]
     */
    function uniq(array) {
      return (array && array.length) ? baseUniq(array) : [];
    }

    /**
     * This method is like `_.uniq` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the criterion by which
     * uniqueness is computed. The order of result values is determined by the
     * order they occur in the array. The iteratee is invoked with one argument:
     * (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
     * // => [2.1, 1.2]
     *
     * // The `_.property` iteratee shorthand.
     * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
     * // => [{ 'x': 1 }, { 'x': 2 }]
     */
    function uniqBy(array, iteratee) {
      return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
    }

    /**
     * This method is like `_.uniq` except that it accepts `comparator` which
     * is invoked to compare elements of `array`. The order of result values is
     * determined by the order they occur in the array.The comparator is invoked
     * with two arguments: (arrVal, othVal).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new duplicate free array.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
     *
     * _.uniqWith(objects, _.isEqual);
     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
     */
    function uniqWith(array, comparator) {
      comparator = typeof comparator == 'function' ? comparator : undefined;
      return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
    }

    /**
     * This method is like `_.zip` except that it accepts an array of grouped
     * elements and creates an array regrouping the elements to their pre-zip
     * configuration.
     *
     * @static
     * @memberOf _
     * @since 1.2.0
     * @category Array
     * @param {Array} array The array of grouped elements to process.
     * @returns {Array} Returns the new array of regrouped elements.
     * @example
     *
     * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
     * // => [['a', 1, true], ['b', 2, false]]
     *
     * _.unzip(zipped);
     * // => [['a', 'b'], [1, 2], [true, false]]
     */
    function unzip(array) {
      if (!(array && array.length)) {
        return [];
      }
      var length = 0;
      array = arrayFilter(array, function(group) {
        if (isArrayLikeObject(group)) {
          length = nativeMax(group.length, length);
          return true;
        }
      });
      return baseTimes(length, function(index) {
        return arrayMap(array, baseProperty(index));
      });
    }

    /**
     * This method is like `_.unzip` except that it accepts `iteratee` to specify
     * how regrouped values should be combined. The iteratee is invoked with the
     * elements of each group: (...group).
     *
     * @static
     * @memberOf _
     * @since 3.8.0
     * @category Array
     * @param {Array} array The array of grouped elements to process.
     * @param {Function} [iteratee=_.identity] The function to combine
     *  regrouped values.
     * @returns {Array} Returns the new array of regrouped elements.
     * @example
     *
     * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
     * // => [[1, 10, 100], [2, 20, 200]]
     *
     * _.unzipWith(zipped, _.add);
     * // => [3, 30, 300]
     */
    function unzipWith(array, iteratee) {
      if (!(array && array.length)) {
        return [];
      }
      var result = unzip(array);
      if (iteratee == null) {
        return result;
      }
      return arrayMap(result, function(group) {
        return apply(iteratee, undefined, group);
      });
    }

    /**
     * Creates an array excluding all given values using
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * for equality comparisons.
     *
     * **Note:** Unlike `_.pull`, this method returns a new array.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {Array} array The array to inspect.
     * @param {...*} [values] The values to exclude.
     * @returns {Array} Returns the new array of filtered values.
     * @see _.difference, _.xor
     * @example
     *
     * _.without([2, 1, 2, 3], 1, 2);
     * // => [3]
     */
    var without = baseRest(function(array, values) {
      return isArrayLikeObject(array)
        ? baseDifference(array, values)
        : [];
    });

    /**
     * Creates an array of unique values that is the
     * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
     * of the given arrays. The order of result values is determined by the order
     * they occur in the arrays.
     *
     * @static
     * @memberOf _
     * @since 2.4.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @returns {Array} Returns the new array of filtered values.
     * @see _.difference, _.without
     * @example
     *
     * _.xor([2, 1], [2, 3]);
     * // => [1, 3]
     */
    var xor = baseRest(function(arrays) {
      return baseXor(arrayFilter(arrays, isArrayLikeObject));
    });

    /**
     * This method is like `_.xor` except that it accepts `iteratee` which is
     * invoked for each element of each `arrays` to generate the criterion by
     * which by which they're compared. The order of result values is determined
     * by the order they occur in the arrays. The iteratee is invoked with one
     * argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Array} Returns the new array of filtered values.
     * @example
     *
     * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
     * // => [1.2, 3.4]
     *
     * // The `_.property` iteratee shorthand.
     * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
     * // => [{ 'x': 2 }]
     */
    var xorBy = baseRest(function(arrays) {
      var iteratee = last(arrays);
      if (isArrayLikeObject(iteratee)) {
        iteratee = undefined;
      }
      return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
    });

    /**
     * This method is like `_.xor` except that it accepts `comparator` which is
     * invoked to compare elements of `arrays`. The order of result values is
     * determined by the order they occur in the arrays. The comparator is invoked
     * with two arguments: (arrVal, othVal).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Array
     * @param {...Array} [arrays] The arrays to inspect.
     * @param {Function} [comparator] The comparator invoked per element.
     * @returns {Array} Returns the new array of filtered values.
     * @example
     *
     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
     *
     * _.xorWith(objects, others, _.isEqual);
     * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
     */
    var xorWith = baseRest(function(arrays) {
      var comparator = last(arrays);
      comparator = typeof comparator == 'function' ? comparator : undefined;
      return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
    });

    /**
     * Creates an array of grouped elements, the first of which contains the
     * first elements of the given arrays, the second of which contains the
     * second elements of the given arrays, and so on.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Array
     * @param {...Array} [arrays] The arrays to process.
     * @returns {Array} Returns the new array of grouped elements.
     * @example
     *
     * _.zip(['a', 'b'], [1, 2], [true, false]);
     * // => [['a', 1, true], ['b', 2, false]]
     */
    var zip = baseRest(unzip);

    /**
     * This method is like `_.fromPairs` except that it accepts two arrays,
     * one of property identifiers and one of corresponding values.
     *
     * @static
     * @memberOf _
     * @since 0.4.0
     * @category Array
     * @param {Array} [props=[]] The property identifiers.
     * @param {Array} [values=[]] The property values.
     * @returns {Object} Returns the new object.
     * @example
     *
     * _.zipObject(['a', 'b'], [1, 2]);
     * // => { 'a': 1, 'b': 2 }
     */
    function zipObject(props, values) {
      return baseZipObject(props || [], values || [], assignValue);
    }

    /**
     * This method is like `_.zipObject` except that it supports property paths.
     *
     * @static
     * @memberOf _
     * @since 4.1.0
     * @category Array
     * @param {Array} [props=[]] The property identifiers.
     * @param {Array} [values=[]] The property values.
     * @returns {Object} Returns the new object.
     * @example
     *
     * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
     * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
     */
    function zipObjectDeep(props, values) {
      return baseZipObject(props || [], values || [], baseSet);
    }

    /**
     * This method is like `_.zip` except that it accepts `iteratee` to specify
     * how grouped values should be combined. The iteratee is invoked with the
     * elements of each group: (...group).
     *
     * @static
     * @memberOf _
     * @since 3.8.0
     * @category Array
     * @param {...Array} [arrays] The arrays to process.
     * @param {Function} [iteratee=_.identity] The function to combine
     *  grouped values.
     * @returns {Array} Returns the new array of grouped elements.
     * @example
     *
     * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
     *   return a + b + c;
     * });
     * // => [111, 222]
     */
    var zipWith = baseRest(function(arrays) {
      var length = arrays.length,
          iteratee = length > 1 ? arrays[length - 1] : undefined;

      iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
      return unzipWith(arrays, iteratee);
    });

    /*------------------------------------------------------------------------*/

    /**
     * Creates a `lodash` wrapper instance that wraps `value` with explicit method
     * chain sequences enabled. The result of such sequences must be unwrapped
     * with `_#value`.
     *
     * @static
     * @memberOf _
     * @since 1.3.0
     * @category Seq
     * @param {*} value The value to wrap.
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'age': 36 },
     *   { 'user': 'fred',    'age': 40 },
     *   { 'user': 'pebbles', 'age': 1 }
     * ];
     *
     * var youngest = _
     *   .chain(users)
     *   .sortBy('age')
     *   .map(function(o) {
     *     return o.user + ' is ' + o.age;
     *   })
     *   .head()
     *   .value();
     * // => 'pebbles is 1'
     */
    function chain(value) {
      var result = lodash(value);
      result.__chain__ = true;
      return result;
    }

    /**
     * This method invokes `interceptor` and returns `value`. The interceptor
     * is invoked with one argument; (value). The purpose of this method is to
     * "tap into" a method chain sequence in order to modify intermediate results.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Seq
     * @param {*} value The value to provide to `interceptor`.
     * @param {Function} interceptor The function to invoke.
     * @returns {*} Returns `value`.
     * @example
     *
     * _([1, 2, 3])
     *  .tap(function(array) {
     *    // Mutate input array.
     *    array.pop();
     *  })
     *  .reverse()
     *  .value();
     * // => [2, 1]
     */
    function tap(value, interceptor) {
      interceptor(value);
      return value;
    }

    /**
     * This method is like `_.tap` except that it returns the result of `interceptor`.
     * The purpose of this method is to "pass thru" values replacing intermediate
     * results in a method chain sequence.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Seq
     * @param {*} value The value to provide to `interceptor`.
     * @param {Function} interceptor The function to invoke.
     * @returns {*} Returns the result of `interceptor`.
     * @example
     *
     * _('  abc  ')
     *  .chain()
     *  .trim()
     *  .thru(function(value) {
     *    return [value];
     *  })
     *  .value();
     * // => ['abc']
     */
    function thru(value, interceptor) {
      return interceptor(value);
    }

    /**
     * This method is the wrapper version of `_.at`.
     *
     * @name at
     * @memberOf _
     * @since 1.0.0
     * @category Seq
     * @param {...(string|string[])} [paths] The property paths to pick.
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
     *
     * _(object).at(['a[0].b.c', 'a[1]']).value();
     * // => [3, 4]
     */
    var wrapperAt = flatRest(function(paths) {
      var length = paths.length,
          start = length ? paths[0] : 0,
          value = this.__wrapped__,
          interceptor = function(object) { return baseAt(object, paths); };

      if (length > 1 || this.__actions__.length ||
          !(value instanceof LazyWrapper) || !isIndex(start)) {
        return this.thru(interceptor);
      }
      value = value.slice(start, +start + (length ? 1 : 0));
      value.__actions__.push({
        'func': thru,
        'args': [interceptor],
        'thisArg': undefined
      });
      return new LodashWrapper(value, this.__chain__).thru(function(array) {
        if (length && !array.length) {
          array.push(undefined);
        }
        return array;
      });
    });

    /**
     * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
     *
     * @name chain
     * @memberOf _
     * @since 0.1.0
     * @category Seq
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * var users = [
     *   { 'user': 'barney', 'age': 36 },
     *   { 'user': 'fred',   'age': 40 }
     * ];
     *
     * // A sequence without explicit chaining.
     * _(users).head();
     * // => { 'user': 'barney', 'age': 36 }
     *
     * // A sequence with explicit chaining.
     * _(users)
     *   .chain()
     *   .head()
     *   .pick('user')
     *   .value();
     * // => { 'user': 'barney' }
     */
    function wrapperChain() {
      return chain(this);
    }

    /**
     * Executes the chain sequence and returns the wrapped result.
     *
     * @name commit
     * @memberOf _
     * @since 3.2.0
     * @category Seq
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * var array = [1, 2];
     * var wrapped = _(array).push(3);
     *
     * console.log(array);
     * // => [1, 2]
     *
     * wrapped = wrapped.commit();
     * console.log(array);
     * // => [1, 2, 3]
     *
     * wrapped.last();
     * // => 3
     *
     * console.log(array);
     * // => [1, 2, 3]
     */
    function wrapperCommit() {
      return new LodashWrapper(this.value(), this.__chain__);
    }

    /**
     * Gets the next value on a wrapped object following the
     * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
     *
     * @name next
     * @memberOf _
     * @since 4.0.0
     * @category Seq
     * @returns {Object} Returns the next iterator value.
     * @example
     *
     * var wrapped = _([1, 2]);
     *
     * wrapped.next();
     * // => { 'done': false, 'value': 1 }
     *
     * wrapped.next();
     * // => { 'done': false, 'value': 2 }
     *
     * wrapped.next();
     * // => { 'done': true, 'value': undefined }
     */
    function wrapperNext() {
      if (this.__values__ === undefined) {
        this.__values__ = toArray(this.value());
      }
      var done = this.__index__ >= this.__values__.length,
          value = done ? undefined : this.__values__[this.__index__++];

      return { 'done': done, 'value': value };
    }

    /**
     * Enables the wrapper to be iterable.
     *
     * @name Symbol.iterator
     * @memberOf _
     * @since 4.0.0
     * @category Seq
     * @returns {Object} Returns the wrapper object.
     * @example
     *
     * var wrapped = _([1, 2]);
     *
     * wrapped[Symbol.iterator]() === wrapped;
     * // => true
     *
     * Array.from(wrapped);
     * // => [1, 2]
     */
    function wrapperToIterator() {
      return this;
    }

    /**
     * Creates a clone of the chain sequence planting `value` as the wrapped value.
     *
     * @name plant
     * @memberOf _
     * @since 3.2.0
     * @category Seq
     * @param {*} value The value to plant.
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * var wrapped = _([1, 2]).map(square);
     * var other = wrapped.plant([3, 4]);
     *
     * other.value();
     * // => [9, 16]
     *
     * wrapped.value();
     * // => [1, 4]
     */
    function wrapperPlant(value) {
      var result,
          parent = this;

      while (parent instanceof baseLodash) {
        var clone = wrapperClone(parent);
        clone.__index__ = 0;
        clone.__values__ = undefined;
        if (result) {
          previous.__wrapped__ = clone;
        } else {
          result = clone;
        }
        var previous = clone;
        parent = parent.__wrapped__;
      }
      previous.__wrapped__ = value;
      return result;
    }

    /**
     * This method is the wrapper version of `_.reverse`.
     *
     * **Note:** This method mutates the wrapped array.
     *
     * @name reverse
     * @memberOf _
     * @since 0.1.0
     * @category Seq
     * @returns {Object} Returns the new `lodash` wrapper instance.
     * @example
     *
     * var array = [1, 2, 3];
     *
     * _(array).reverse().value()
     * // => [3, 2, 1]
     *
     * console.log(array);
     * // => [3, 2, 1]
     */
    function wrapperReverse() {
      var value = this.__wrapped__;
      if (value instanceof LazyWrapper) {
        var wrapped = value;
        if (this.__actions__.length) {
          wrapped = new LazyWrapper(this);
        }
        wrapped = wrapped.reverse();
        wrapped.__actions__.push({
          'func': thru,
          'args': [reverse],
          'thisArg': undefined
        });
        return new LodashWrapper(wrapped, this.__chain__);
      }
      return this.thru(reverse);
    }

    /**
     * Executes the chain sequence to resolve the unwrapped value.
     *
     * @name value
     * @memberOf _
     * @since 0.1.0
     * @alias toJSON, valueOf
     * @category Seq
     * @returns {*} Returns the resolved unwrapped value.
     * @example
     *
     * _([1, 2, 3]).value();
     * // => [1, 2, 3]
     */
    function wrapperValue() {
      return baseWrapperValue(this.__wrapped__, this.__actions__);
    }

    /*------------------------------------------------------------------------*/

    /**
     * Creates an object composed of keys generated from the results of running
     * each element of `collection` thru `iteratee`. The corresponding value of
     * each key is the number of times the key was returned by `iteratee`. The
     * iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 0.5.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
     * @returns {Object} Returns the composed aggregate object.
     * @example
     *
     * _.countBy([6.1, 4.2, 6.3], Math.floor);
     * // => { '4': 1, '6': 2 }
     *
     * // The `_.property` iteratee shorthand.
     * _.countBy(['one', 'two', 'three'], 'length');
     * // => { '3': 2, '5': 1 }
     */
    var countBy = createAggregator(function(result, value, key) {
      if (hasOwnProperty.call(result, key)) {
        ++result[key];
      } else {
        baseAssignValue(result, key, 1);
      }
    });

    /**
     * Checks if `predicate` returns truthy for **all** elements of `collection`.
     * Iteration is stopped once `predicate` returns falsey. The predicate is
     * invoked with three arguments: (value, index|key, collection).
     *
     * **Note:** This method returns `true` for
     * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
     * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
     * elements of empty collections.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {boolean} Returns `true` if all elements pass the predicate check,
     *  else `false`.
     * @example
     *
     * _.every([true, 1, null, 'yes'], Boolean);
     * // => false
     *
     * var users = [
     *   { 'user': 'barney', 'age': 36, 'active': false },
     *   { 'user': 'fred',   'age': 40, 'active': false }
     * ];
     *
     * // The `_.matches` iteratee shorthand.
     * _.every(users, { 'user': 'barney', 'active': false });
     * // => false
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.every(users, ['active', false]);
     * // => true
     *
     * // The `_.property` iteratee shorthand.
     * _.every(users, 'active');
     * // => false
     */
    function every(collection, predicate, guard) {
      var func = isArray(collection) ? arrayEvery : baseEvery;
      if (guard && isIterateeCall(collection, predicate, guard)) {
        predicate = undefined;
      }
      return func(collection, getIteratee(predicate, 3));
    }

    /**
     * Iterates over elements of `collection`, returning an array of all elements
     * `predicate` returns truthy for. The predicate is invoked with three
     * arguments: (value, index|key, collection).
     *
     * **Note:** Unlike `_.remove`, this method returns a new array.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new filtered array.
     * @see _.reject
     * @example
     *
     * var users = [
     *   { 'user': 'barney', 'age': 36, 'active': true },
     *   { 'user': 'fred',   'age': 40, 'active': false }
     * ];
     *
     * _.filter(users, function(o) { return !o.active; });
     * // => objects for ['fred']
     *
     * // The `_.matches` iteratee shorthand.
     * _.filter(users, { 'age': 36, 'active': true });
     * // => objects for ['barney']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.filter(users, ['active', false]);
     * // => objects for ['fred']
     *
     * // The `_.property` iteratee shorthand.
     * _.filter(users, 'active');
     * // => objects for ['barney']
     *
     * // Combining several predicates using `_.overEvery` or `_.overSome`.
     * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));
     * // => objects for ['fred', 'barney']
     */
    function filter(collection, predicate) {
      var func = isArray(collection) ? arrayFilter : baseFilter;
      return func(collection, getIteratee(predicate, 3));
    }

    /**
     * Iterates over elements of `collection`, returning the first element
     * `predicate` returns truthy for. The predicate is invoked with three
     * arguments: (value, index|key, collection).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param {number} [fromIndex=0] The index to search from.
     * @returns {*} Returns the matched element, else `undefined`.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'age': 36, 'active': true },
     *   { 'user': 'fred',    'age': 40, 'active': false },
     *   { 'user': 'pebbles', 'age': 1,  'active': true }
     * ];
     *
     * _.find(users, function(o) { return o.age < 40; });
     * // => object for 'barney'
     *
     * // The `_.matches` iteratee shorthand.
     * _.find(users, { 'age': 1, 'active': true });
     * // => object for 'pebbles'
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.find(users, ['active', false]);
     * // => object for 'fred'
     *
     * // The `_.property` iteratee shorthand.
     * _.find(users, 'active');
     * // => object for 'barney'
     */
    var find = createFind(findIndex);

    /**
     * This method is like `_.find` except that it iterates over elements of
     * `collection` from right to left.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param {number} [fromIndex=collection.length-1] The index to search from.
     * @returns {*} Returns the matched element, else `undefined`.
     * @example
     *
     * _.findLast([1, 2, 3, 4], function(n) {
     *   return n % 2 == 1;
     * });
     * // => 3
     */
    var findLast = createFind(findLastIndex);

    /**
     * Creates a flattened array of values by running each element in `collection`
     * thru `iteratee` and flattening the mapped results. The iteratee is invoked
     * with three arguments: (value, index|key, collection).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * function duplicate(n) {
     *   return [n, n];
     * }
     *
     * _.flatMap([1, 2], duplicate);
     * // => [1, 1, 2, 2]
     */
    function flatMap(collection, iteratee) {
      return baseFlatten(map(collection, iteratee), 1);
    }

    /**
     * This method is like `_.flatMap` except that it recursively flattens the
     * mapped results.
     *
     * @static
     * @memberOf _
     * @since 4.7.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * function duplicate(n) {
     *   return [[[n, n]]];
     * }
     *
     * _.flatMapDeep([1, 2], duplicate);
     * // => [1, 1, 2, 2]
     */
    function flatMapDeep(collection, iteratee) {
      return baseFlatten(map(collection, iteratee), INFINITY);
    }

    /**
     * This method is like `_.flatMap` except that it recursively flattens the
     * mapped results up to `depth` times.
     *
     * @static
     * @memberOf _
     * @since 4.7.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @param {number} [depth=1] The maximum recursion depth.
     * @returns {Array} Returns the new flattened array.
     * @example
     *
     * function duplicate(n) {
     *   return [[[n, n]]];
     * }
     *
     * _.flatMapDepth([1, 2], duplicate, 2);
     * // => [[1, 1], [2, 2]]
     */
    function flatMapDepth(collection, iteratee, depth) {
      depth = depth === undefined ? 1 : toInteger(depth);
      return baseFlatten(map(collection, iteratee), depth);
    }

    /**
     * Iterates over elements of `collection` and invokes `iteratee` for each element.
     * The iteratee is invoked with three arguments: (value, index|key, collection).
     * Iteratee functions may exit iteration early by explicitly returning `false`.
     *
     * **Note:** As with other "Collections" methods, objects with a "length"
     * property are iterated like arrays. To avoid this behavior use `_.forIn`
     * or `_.forOwn` for object iteration.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @alias each
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array|Object} Returns `collection`.
     * @see _.forEachRight
     * @example
     *
     * _.forEach([1, 2], function(value) {
     *   console.log(value);
     * });
     * // => Logs `1` then `2`.
     *
     * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
     *   console.log(key);
     * });
     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
     */
    function forEach(collection, iteratee) {
      var func = isArray(collection) ? arrayEach : baseEach;
      return func(collection, getIteratee(iteratee, 3));
    }

    /**
     * This method is like `_.forEach` except that it iterates over elements of
     * `collection` from right to left.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @alias eachRight
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array|Object} Returns `collection`.
     * @see _.forEach
     * @example
     *
     * _.forEachRight([1, 2], function(value) {
     *   console.log(value);
     * });
     * // => Logs `2` then `1`.
     */
    function forEachRight(collection, iteratee) {
      var func = isArray(collection) ? arrayEachRight : baseEachRight;
      return func(collection, getIteratee(iteratee, 3));
    }

    /**
     * Creates an object composed of keys generated from the results of running
     * each element of `collection` thru `iteratee`. The order of grouped values
     * is determined by the order they occur in `collection`. The corresponding
     * value of each key is an array of elements responsible for generating the
     * key. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
     * @returns {Object} Returns the composed aggregate object.
     * @example
     *
     * _.groupBy([6.1, 4.2, 6.3], Math.floor);
     * // => { '4': [4.2], '6': [6.1, 6.3] }
     *
     * // The `_.property` iteratee shorthand.
     * _.groupBy(['one', 'two', 'three'], 'length');
     * // => { '3': ['one', 'two'], '5': ['three'] }
     */
    var groupBy = createAggregator(function(result, value, key) {
      if (hasOwnProperty.call(result, key)) {
        result[key].push(value);
      } else {
        baseAssignValue(result, key, [value]);
      }
    });

    /**
     * Checks if `value` is in `collection`. If `collection` is a string, it's
     * checked for a substring of `value`, otherwise
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * is used for equality comparisons. If `fromIndex` is negative, it's used as
     * the offset from the end of `collection`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object|string} collection The collection to inspect.
     * @param {*} value The value to search for.
     * @param {number} [fromIndex=0] The index to search from.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
     * @returns {boolean} Returns `true` if `value` is found, else `false`.
     * @example
     *
     * _.includes([1, 2, 3], 1);
     * // => true
     *
     * _.includes([1, 2, 3], 1, 2);
     * // => false
     *
     * _.includes({ 'a': 1, 'b': 2 }, 1);
     * // => true
     *
     * _.includes('abcd', 'bc');
     * // => true
     */
    function includes(collection, value, fromIndex, guard) {
      collection = isArrayLike(collection) ? collection : values(collection);
      fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;

      var length = collection.length;
      if (fromIndex < 0) {
        fromIndex = nativeMax(length + fromIndex, 0);
      }
      return isString(collection)
        ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
        : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
    }

    /**
     * Invokes the method at `path` of each element in `collection`, returning
     * an array of the results of each invoked method. Any additional arguments
     * are provided to each invoked method. If `path` is a function, it's invoked
     * for, and `this` bound to, each element in `collection`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Array|Function|string} path The path of the method to invoke or
     *  the function invoked per iteration.
     * @param {...*} [args] The arguments to invoke each method with.
     * @returns {Array} Returns the array of results.
     * @example
     *
     * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
     * // => [[1, 5, 7], [1, 2, 3]]
     *
     * _.invokeMap([123, 456], String.prototype.split, '');
     * // => [['1', '2', '3'], ['4', '5', '6']]
     */
    var invokeMap = baseRest(function(collection, path, args) {
      var index = -1,
          isFunc = typeof path == 'function',
          result = isArrayLike(collection) ? Array(collection.length) : [];

      baseEach(collection, function(value) {
        result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
      });
      return result;
    });

    /**
     * Creates an object composed of keys generated from the results of running
     * each element of `collection` thru `iteratee`. The corresponding value of
     * each key is the last element responsible for generating the key. The
     * iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
     * @returns {Object} Returns the composed aggregate object.
     * @example
     *
     * var array = [
     *   { 'dir': 'left', 'code': 97 },
     *   { 'dir': 'right', 'code': 100 }
     * ];
     *
     * _.keyBy(array, function(o) {
     *   return String.fromCharCode(o.code);
     * });
     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
     *
     * _.keyBy(array, 'dir');
     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
     */
    var keyBy = createAggregator(function(result, value, key) {
      baseAssignValue(result, key, value);
    });

    /**
     * Creates an array of values by running each element in `collection` thru
     * `iteratee`. The iteratee is invoked with three arguments:
     * (value, index|key, collection).
     *
     * Many lodash methods are guarded to work as iteratees for methods like
     * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
     *
     * The guarded methods are:
     * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
     * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
     * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
     * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new mapped array.
     * @example
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * _.map([4, 8], square);
     * // => [16, 64]
     *
     * _.map({ 'a': 4, 'b': 8 }, square);
     * // => [16, 64] (iteration order is not guaranteed)
     *
     * var users = [
     *   { 'user': 'barney' },
     *   { 'user': 'fred' }
     * ];
     *
     * // The `_.property` iteratee shorthand.
     * _.map(users, 'user');
     * // => ['barney', 'fred']
     */
    function map(collection, iteratee) {
      var func = isArray(collection) ? arrayMap : baseMap;
      return func(collection, getIteratee(iteratee, 3));
    }

    /**
     * This method is like `_.sortBy` except that it allows specifying the sort
     * orders of the iteratees to sort by. If `orders` is unspecified, all values
     * are sorted in ascending order. Otherwise, specify an order of "desc" for
     * descending or "asc" for ascending sort order of corresponding values.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
     *  The iteratees to sort by.
     * @param {string[]} [orders] The sort orders of `iteratees`.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
     * @returns {Array} Returns the new sorted array.
     * @example
     *
     * var users = [
     *   { 'user': 'fred',   'age': 48 },
     *   { 'user': 'barney', 'age': 34 },
     *   { 'user': 'fred',   'age': 40 },
     *   { 'user': 'barney', 'age': 36 }
     * ];
     *
     * // Sort by `user` in ascending order and by `age` in descending order.
     * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
     */
    function orderBy(collection, iteratees, orders, guard) {
      if (collection == null) {
        return [];
      }
      if (!isArray(iteratees)) {
        iteratees = iteratees == null ? [] : [iteratees];
      }
      orders = guard ? undefined : orders;
      if (!isArray(orders)) {
        orders = orders == null ? [] : [orders];
      }
      return baseOrderBy(collection, iteratees, orders);
    }

    /**
     * Creates an array of elements split into two groups, the first of which
     * contains elements `predicate` returns truthy for, the second of which
     * contains elements `predicate` returns falsey for. The predicate is
     * invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the array of grouped elements.
     * @example
     *
     * var users = [
     *   { 'user': 'barney',  'age': 36, 'active': false },
     *   { 'user': 'fred',    'age': 40, 'active': true },
     *   { 'user': 'pebbles', 'age': 1,  'active': false }
     * ];
     *
     * _.partition(users, function(o) { return o.active; });
     * // => objects for [['fred'], ['barney', 'pebbles']]
     *
     * // The `_.matches` iteratee shorthand.
     * _.partition(users, { 'age': 1, 'active': false });
     * // => objects for [['pebbles'], ['barney', 'fred']]
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.partition(users, ['active', false]);
     * // => objects for [['barney', 'pebbles'], ['fred']]
     *
     * // The `_.property` iteratee shorthand.
     * _.partition(users, 'active');
     * // => objects for [['fred'], ['barney', 'pebbles']]
     */
    var partition = createAggregator(function(result, value, key) {
      result[key ? 0 : 1].push(value);
    }, function() { return [[], []]; });

    /**
     * Reduces `collection` to a value which is the accumulated result of running
     * each element in `collection` thru `iteratee`, where each successive
     * invocation is supplied the return value of the previous. If `accumulator`
     * is not given, the first element of `collection` is used as the initial
     * value. The iteratee is invoked with four arguments:
     * (accumulator, value, index|key, collection).
     *
     * Many lodash methods are guarded to work as iteratees for methods like
     * `_.reduce`, `_.reduceRight`, and `_.transform`.
     *
     * The guarded methods are:
     * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
     * and `sortBy`
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @param {*} [accumulator] The initial value.
     * @returns {*} Returns the accumulated value.
     * @see _.reduceRight
     * @example
     *
     * _.reduce([1, 2], function(sum, n) {
     *   return sum + n;
     * }, 0);
     * // => 3
     *
     * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
     *   (result[value] || (result[value] = [])).push(key);
     *   return result;
     * }, {});
     * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
     */
    function reduce(collection, iteratee, accumulator) {
      var func = isArray(collection) ? arrayReduce : baseReduce,
          initAccum = arguments.length < 3;

      return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
    }

    /**
     * This method is like `_.reduce` except that it iterates over elements of
     * `collection` from right to left.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @param {*} [accumulator] The initial value.
     * @returns {*} Returns the accumulated value.
     * @see _.reduce
     * @example
     *
     * var array = [[0, 1], [2, 3], [4, 5]];
     *
     * _.reduceRight(array, function(flattened, other) {
     *   return flattened.concat(other);
     * }, []);
     * // => [4, 5, 2, 3, 0, 1]
     */
    function reduceRight(collection, iteratee, accumulator) {
      var func = isArray(collection) ? arrayReduceRight : baseReduce,
          initAccum = arguments.length < 3;

      return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
    }

    /**
     * The opposite of `_.filter`; this method returns the elements of `collection`
     * that `predicate` does **not** return truthy for.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the new filtered array.
     * @see _.filter
     * @example
     *
     * var users = [
     *   { 'user': 'barney', 'age': 36, 'active': false },
     *   { 'user': 'fred',   'age': 40, 'active': true }
     * ];
     *
     * _.reject(users, function(o) { return !o.active; });
     * // => objects for ['fred']
     *
     * // The `_.matches` iteratee shorthand.
     * _.reject(users, { 'age': 40, 'active': true });
     * // => objects for ['barney']
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.reject(users, ['active', false]);
     * // => objects for ['fred']
     *
     * // The `_.property` iteratee shorthand.
     * _.reject(users, 'active');
     * // => objects for ['barney']
     */
    function reject(collection, predicate) {
      var func = isArray(collection) ? arrayFilter : baseFilter;
      return func(collection, negate(getIteratee(predicate, 3)));
    }

    /**
     * Gets a random element from `collection`.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to sample.
     * @returns {*} Returns the random element.
     * @example
     *
     * _.sample([1, 2, 3, 4]);
     * // => 2
     */
    function sample(collection) {
      var func = isArray(collection) ? arraySample : baseSample;
      return func(collection);
    }

    /**
     * Gets `n` random elements at unique keys from `collection` up to the
     * size of `collection`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Collection
     * @param {Array|Object} collection The collection to sample.
     * @param {number} [n=1] The number of elements to sample.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the random elements.
     * @example
     *
     * _.sampleSize([1, 2, 3], 2);
     * // => [3, 1]
     *
     * _.sampleSize([1, 2, 3], 4);
     * // => [2, 3, 1]
     */
    function sampleSize(collection, n, guard) {
      if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
        n = 1;
      } else {
        n = toInteger(n);
      }
      var func = isArray(collection) ? arraySampleSize : baseSampleSize;
      return func(collection, n);
    }

    /**
     * Creates an array of shuffled values, using a version of the
     * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to shuffle.
     * @returns {Array} Returns the new shuffled array.
     * @example
     *
     * _.shuffle([1, 2, 3, 4]);
     * // => [4, 1, 3, 2]
     */
    function shuffle(collection) {
      var func = isArray(collection) ? arrayShuffle : baseShuffle;
      return func(collection);
    }

    /**
     * Gets the size of `collection` by returning its length for array-like
     * values or the number of own enumerable string keyed properties for objects.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object|string} collection The collection to inspect.
     * @returns {number} Returns the collection size.
     * @example
     *
     * _.size([1, 2, 3]);
     * // => 3
     *
     * _.size({ 'a': 1, 'b': 2 });
     * // => 2
     *
     * _.size('pebbles');
     * // => 7
     */
    function size(collection) {
      if (collection == null) {
        return 0;
      }
      if (isArrayLike(collection)) {
        return isString(collection) ? stringSize(collection) : collection.length;
      }
      var tag = getTag(collection);
      if (tag == mapTag || tag == setTag) {
        return collection.size;
      }
      return baseKeys(collection).length;
    }

    /**
     * Checks if `predicate` returns truthy for **any** element of `collection`.
     * Iteration is stopped once `predicate` returns truthy. The predicate is
     * invoked with three arguments: (value, index|key, collection).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {boolean} Returns `true` if any element passes the predicate check,
     *  else `false`.
     * @example
     *
     * _.some([null, 0, 'yes', false], Boolean);
     * // => true
     *
     * var users = [
     *   { 'user': 'barney', 'active': true },
     *   { 'user': 'fred',   'active': false }
     * ];
     *
     * // The `_.matches` iteratee shorthand.
     * _.some(users, { 'user': 'barney', 'active': false });
     * // => false
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.some(users, ['active', false]);
     * // => true
     *
     * // The `_.property` iteratee shorthand.
     * _.some(users, 'active');
     * // => true
     */
    function some(collection, predicate, guard) {
      var func = isArray(collection) ? arraySome : baseSome;
      if (guard && isIterateeCall(collection, predicate, guard)) {
        predicate = undefined;
      }
      return func(collection, getIteratee(predicate, 3));
    }

    /**
     * Creates an array of elements, sorted in ascending order by the results of
     * running each element in a collection thru each iteratee. This method
     * performs a stable sort, that is, it preserves the original sort order of
     * equal elements. The iteratees are invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Collection
     * @param {Array|Object} collection The collection to iterate over.
     * @param {...(Function|Function[])} [iteratees=[_.identity]]
     *  The iteratees to sort by.
     * @returns {Array} Returns the new sorted array.
     * @example
     *
     * var users = [
     *   { 'user': 'fred',   'age': 48 },
     *   { 'user': 'barney', 'age': 36 },
     *   { 'user': 'fred',   'age': 30 },
     *   { 'user': 'barney', 'age': 34 }
     * ];
     *
     * _.sortBy(users, [function(o) { return o.user; }]);
     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 30]]
     *
     * _.sortBy(users, ['user', 'age']);
     * // => objects for [['barney', 34], ['barney', 36], ['fred', 30], ['fred', 48]]
     */
    var sortBy = baseRest(function(collection, iteratees) {
      if (collection == null) {
        return [];
      }
      var length = iteratees.length;
      if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
        iteratees = [];
      } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
        iteratees = [iteratees[0]];
      }
      return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
    });

    /*------------------------------------------------------------------------*/

    /**
     * Gets the timestamp of the number of milliseconds that have elapsed since
     * the Unix epoch (1 January 1970 00:00:00 UTC).
     *
     * @static
     * @memberOf _
     * @since 2.4.0
     * @category Date
     * @returns {number} Returns the timestamp.
     * @example
     *
     * _.defer(function(stamp) {
     *   console.log(_.now() - stamp);
     * }, _.now());
     * // => Logs the number of milliseconds it took for the deferred invocation.
     */
    var now = ctxNow || function() {
      return root.Date.now();
    };

    /*------------------------------------------------------------------------*/

    /**
     * The opposite of `_.before`; this method creates a function that invokes
     * `func` once it's called `n` or more times.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {number} n The number of calls before `func` is invoked.
     * @param {Function} func The function to restrict.
     * @returns {Function} Returns the new restricted function.
     * @example
     *
     * var saves = ['profile', 'settings'];
     *
     * var done = _.after(saves.length, function() {
     *   console.log('done saving!');
     * });
     *
     * _.forEach(saves, function(type) {
     *   asyncSave({ 'type': type, 'complete': done });
     * });
     * // => Logs 'done saving!' after the two async saves have completed.
     */
    function after(n, func) {
      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      n = toInteger(n);
      return function() {
        if (--n < 1) {
          return func.apply(this, arguments);
        }
      };
    }

    /**
     * Creates a function that invokes `func`, with up to `n` arguments,
     * ignoring any additional arguments.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Function
     * @param {Function} func The function to cap arguments for.
     * @param {number} [n=func.length] The arity cap.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Function} Returns the new capped function.
     * @example
     *
     * _.map(['6', '8', '10'], _.ary(parseInt, 1));
     * // => [6, 8, 10]
     */
    function ary(func, n, guard) {
      n = guard ? undefined : n;
      n = (func && n == null) ? func.length : n;
      return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
    }

    /**
     * Creates a function that invokes `func`, with the `this` binding and arguments
     * of the created function, while it's called less than `n` times. Subsequent
     * calls to the created function return the result of the last `func` invocation.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Function
     * @param {number} n The number of calls at which `func` is no longer invoked.
     * @param {Function} func The function to restrict.
     * @returns {Function} Returns the new restricted function.
     * @example
     *
     * jQuery(element).on('click', _.before(5, addContactToList));
     * // => Allows adding up to 4 contacts to the list.
     */
    function before(n, func) {
      var result;
      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      n = toInteger(n);
      return function() {
        if (--n > 0) {
          result = func.apply(this, arguments);
        }
        if (n <= 1) {
          func = undefined;
        }
        return result;
      };
    }

    /**
     * Creates a function that invokes `func` with the `this` binding of `thisArg`
     * and `partials` prepended to the arguments it receives.
     *
     * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
     * may be used as a placeholder for partially applied arguments.
     *
     * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
     * property of bound functions.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to bind.
     * @param {*} thisArg The `this` binding of `func`.
     * @param {...*} [partials] The arguments to be partially applied.
     * @returns {Function} Returns the new bound function.
     * @example
     *
     * function greet(greeting, punctuation) {
     *   return greeting + ' ' + this.user + punctuation;
     * }
     *
     * var object = { 'user': 'fred' };
     *
     * var bound = _.bind(greet, object, 'hi');
     * bound('!');
     * // => 'hi fred!'
     *
     * // Bound with placeholders.
     * var bound = _.bind(greet, object, _, '!');
     * bound('hi');
     * // => 'hi fred!'
     */
    var bind = baseRest(function(func, thisArg, partials) {
      var bitmask = WRAP_BIND_FLAG;
      if (partials.length) {
        var holders = replaceHolders(partials, getHolder(bind));
        bitmask |= WRAP_PARTIAL_FLAG;
      }
      return createWrap(func, bitmask, thisArg, partials, holders);
    });

    /**
     * Creates a function that invokes the method at `object[key]` with `partials`
     * prepended to the arguments it receives.
     *
     * This method differs from `_.bind` by allowing bound functions to reference
     * methods that may be redefined or don't yet exist. See
     * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
     * for more details.
     *
     * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
     * builds, may be used as a placeholder for partially applied arguments.
     *
     * @static
     * @memberOf _
     * @since 0.10.0
     * @category Function
     * @param {Object} object The object to invoke the method on.
     * @param {string} key The key of the method.
     * @param {...*} [partials] The arguments to be partially applied.
     * @returns {Function} Returns the new bound function.
     * @example
     *
     * var object = {
     *   'user': 'fred',
     *   'greet': function(greeting, punctuation) {
     *     return greeting + ' ' + this.user + punctuation;
     *   }
     * };
     *
     * var bound = _.bindKey(object, 'greet', 'hi');
     * bound('!');
     * // => 'hi fred!'
     *
     * object.greet = function(greeting, punctuation) {
     *   return greeting + 'ya ' + this.user + punctuation;
     * };
     *
     * bound('!');
     * // => 'hiya fred!'
     *
     * // Bound with placeholders.
     * var bound = _.bindKey(object, 'greet', _, '!');
     * bound('hi');
     * // => 'hiya fred!'
     */
    var bindKey = baseRest(function(object, key, partials) {
      var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
      if (partials.length) {
        var holders = replaceHolders(partials, getHolder(bindKey));
        bitmask |= WRAP_PARTIAL_FLAG;
      }
      return createWrap(key, bitmask, object, partials, holders);
    });

    /**
     * Creates a function that accepts arguments of `func` and either invokes
     * `func` returning its result, if at least `arity` number of arguments have
     * been provided, or returns a function that accepts the remaining `func`
     * arguments, and so on. The arity of `func` may be specified if `func.length`
     * is not sufficient.
     *
     * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
     * may be used as a placeholder for provided arguments.
     *
     * **Note:** This method doesn't set the "length" property of curried functions.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Function
     * @param {Function} func The function to curry.
     * @param {number} [arity=func.length] The arity of `func`.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Function} Returns the new curried function.
     * @example
     *
     * var abc = function(a, b, c) {
     *   return [a, b, c];
     * };
     *
     * var curried = _.curry(abc);
     *
     * curried(1)(2)(3);
     * // => [1, 2, 3]
     *
     * curried(1, 2)(3);
     * // => [1, 2, 3]
     *
     * curried(1, 2, 3);
     * // => [1, 2, 3]
     *
     * // Curried with placeholders.
     * curried(1)(_, 3)(2);
     * // => [1, 2, 3]
     */
    function curry(func, arity, guard) {
      arity = guard ? undefined : arity;
      var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
      result.placeholder = curry.placeholder;
      return result;
    }

    /**
     * This method is like `_.curry` except that arguments are applied to `func`
     * in the manner of `_.partialRight` instead of `_.partial`.
     *
     * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
     * builds, may be used as a placeholder for provided arguments.
     *
     * **Note:** This method doesn't set the "length" property of curried functions.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Function
     * @param {Function} func The function to curry.
     * @param {number} [arity=func.length] The arity of `func`.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Function} Returns the new curried function.
     * @example
     *
     * var abc = function(a, b, c) {
     *   return [a, b, c];
     * };
     *
     * var curried = _.curryRight(abc);
     *
     * curried(3)(2)(1);
     * // => [1, 2, 3]
     *
     * curried(2, 3)(1);
     * // => [1, 2, 3]
     *
     * curried(1, 2, 3);
     * // => [1, 2, 3]
     *
     * // Curried with placeholders.
     * curried(3)(1, _)(2);
     * // => [1, 2, 3]
     */
    function curryRight(func, arity, guard) {
      arity = guard ? undefined : arity;
      var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
      result.placeholder = curryRight.placeholder;
      return result;
    }

    /**
     * Creates a debounced function that delays invoking `func` until after `wait`
     * milliseconds have elapsed since the last time the debounced function was
     * invoked. The debounced function comes with a `cancel` method to cancel
     * delayed `func` invocations and a `flush` method to immediately invoke them.
     * Provide `options` to indicate whether `func` should be invoked on the
     * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
     * with the last arguments provided to the debounced function. Subsequent
     * calls to the debounced function return the result of the last `func`
     * invocation.
     *
     * **Note:** If `leading` and `trailing` options are `true`, `func` is
     * invoked on the trailing edge of the timeout only if the debounced function
     * is invoked more than once during the `wait` timeout.
     *
     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
     *
     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
     * for details over the differences between `_.debounce` and `_.throttle`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to debounce.
     * @param {number} [wait=0] The number of milliseconds to delay.
     * @param {Object} [options={}] The options object.
     * @param {boolean} [options.leading=false]
     *  Specify invoking on the leading edge of the timeout.
     * @param {number} [options.maxWait]
     *  The maximum time `func` is allowed to be delayed before it's invoked.
     * @param {boolean} [options.trailing=true]
     *  Specify invoking on the trailing edge of the timeout.
     * @returns {Function} Returns the new debounced function.
     * @example
     *
     * // Avoid costly calculations while the window size is in flux.
     * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
     *
     * // Invoke `sendMail` when clicked, debouncing subsequent calls.
     * jQuery(element).on('click', _.debounce(sendMail, 300, {
     *   'leading': true,
     *   'trailing': false
     * }));
     *
     * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
     * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
     * var source = new EventSource('/stream');
     * jQuery(source).on('message', debounced);
     *
     * // Cancel the trailing debounced invocation.
     * jQuery(window).on('popstate', debounced.cancel);
     */
    function debounce(func, wait, options) {
      var lastArgs,
          lastThis,
          maxWait,
          result,
          timerId,
          lastCallTime,
          lastInvokeTime = 0,
          leading = false,
          maxing = false,
          trailing = true;

      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      wait = toNumber(wait) || 0;
      if (isObject(options)) {
        leading = !!options.leading;
        maxing = 'maxWait' in options;
        maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
        trailing = 'trailing' in options ? !!options.trailing : trailing;
      }

      function invokeFunc(time) {
        var args = lastArgs,
            thisArg = lastThis;

        lastArgs = lastThis = undefined;
        lastInvokeTime = time;
        result = func.apply(thisArg, args);
        return result;
      }

      function leadingEdge(time) {
        // Reset any `maxWait` timer.
        lastInvokeTime = time;
        // Start the timer for the trailing edge.
        timerId = setTimeout(timerExpired, wait);
        // Invoke the leading edge.
        return leading ? invokeFunc(time) : result;
      }

      function remainingWait(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime,
            timeWaiting = wait - timeSinceLastCall;

        return maxing
          ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
          : timeWaiting;
      }

      function shouldInvoke(time) {
        var timeSinceLastCall = time - lastCallTime,
            timeSinceLastInvoke = time - lastInvokeTime;

        // Either this is the first call, activity has stopped and we're at the
        // trailing edge, the system time has gone backwards and we're treating
        // it as the trailing edge, or we've hit the `maxWait` limit.
        return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
          (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
      }

      function timerExpired() {
        var time = now();
        if (shouldInvoke(time)) {
          return trailingEdge(time);
        }
        // Restart the timer.
        timerId = setTimeout(timerExpired, remainingWait(time));
      }

      function trailingEdge(time) {
        timerId = undefined;

        // Only invoke if we have `lastArgs` which means `func` has been
        // debounced at least once.
        if (trailing && lastArgs) {
          return invokeFunc(time);
        }
        lastArgs = lastThis = undefined;
        return result;
      }

      function cancel() {
        if (timerId !== undefined) {
          clearTimeout(timerId);
        }
        lastInvokeTime = 0;
        lastArgs = lastCallTime = lastThis = timerId = undefined;
      }

      function flush() {
        return timerId === undefined ? result : trailingEdge(now());
      }

      function debounced() {
        var time = now(),
            isInvoking = shouldInvoke(time);

        lastArgs = arguments;
        lastThis = this;
        lastCallTime = time;

        if (isInvoking) {
          if (timerId === undefined) {
            return leadingEdge(lastCallTime);
          }
          if (maxing) {
            // Handle invocations in a tight loop.
            clearTimeout(timerId);
            timerId = setTimeout(timerExpired, wait);
            return invokeFunc(lastCallTime);
          }
        }
        if (timerId === undefined) {
          timerId = setTimeout(timerExpired, wait);
        }
        return result;
      }
      debounced.cancel = cancel;
      debounced.flush = flush;
      return debounced;
    }

    /**
     * Defers invoking the `func` until the current call stack has cleared. Any
     * additional arguments are provided to `func` when it's invoked.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to defer.
     * @param {...*} [args] The arguments to invoke `func` with.
     * @returns {number} Returns the timer id.
     * @example
     *
     * _.defer(function(text) {
     *   console.log(text);
     * }, 'deferred');
     * // => Logs 'deferred' after one millisecond.
     */
    var defer = baseRest(function(func, args) {
      return baseDelay(func, 1, args);
    });

    /**
     * Invokes `func` after `wait` milliseconds. Any additional arguments are
     * provided to `func` when it's invoked.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to delay.
     * @param {number} wait The number of milliseconds to delay invocation.
     * @param {...*} [args] The arguments to invoke `func` with.
     * @returns {number} Returns the timer id.
     * @example
     *
     * _.delay(function(text) {
     *   console.log(text);
     * }, 1000, 'later');
     * // => Logs 'later' after one second.
     */
    var delay = baseRest(function(func, wait, args) {
      return baseDelay(func, toNumber(wait) || 0, args);
    });

    /**
     * Creates a function that invokes `func` with arguments reversed.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Function
     * @param {Function} func The function to flip arguments for.
     * @returns {Function} Returns the new flipped function.
     * @example
     *
     * var flipped = _.flip(function() {
     *   return _.toArray(arguments);
     * });
     *
     * flipped('a', 'b', 'c', 'd');
     * // => ['d', 'c', 'b', 'a']
     */
    function flip(func) {
      return createWrap(func, WRAP_FLIP_FLAG);
    }

    /**
     * Creates a function that memoizes the result of `func`. If `resolver` is
     * provided, it determines the cache key for storing the result based on the
     * arguments provided to the memoized function. By default, the first argument
     * provided to the memoized function is used as the map cache key. The `func`
     * is invoked with the `this` binding of the memoized function.
     *
     * **Note:** The cache is exposed as the `cache` property on the memoized
     * function. Its creation may be customized by replacing the `_.memoize.Cache`
     * constructor with one whose instances implement the
     * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
     * method interface of `clear`, `delete`, `get`, `has`, and `set`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to have its output memoized.
     * @param {Function} [resolver] The function to resolve the cache key.
     * @returns {Function} Returns the new memoized function.
     * @example
     *
     * var object = { 'a': 1, 'b': 2 };
     * var other = { 'c': 3, 'd': 4 };
     *
     * var values = _.memoize(_.values);
     * values(object);
     * // => [1, 2]
     *
     * values(other);
     * // => [3, 4]
     *
     * object.a = 2;
     * values(object);
     * // => [1, 2]
     *
     * // Modify the result cache.
     * values.cache.set(object, ['a', 'b']);
     * values(object);
     * // => ['a', 'b']
     *
     * // Replace `_.memoize.Cache`.
     * _.memoize.Cache = WeakMap;
     */
    function memoize(func, resolver) {
      if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      var memoized = function() {
        var args = arguments,
            key = resolver ? resolver.apply(this, args) : args[0],
            cache = memoized.cache;

        if (cache.has(key)) {
          return cache.get(key);
        }
        var result = func.apply(this, args);
        memoized.cache = cache.set(key, result) || cache;
        return result;
      };
      memoized.cache = new (memoize.Cache || MapCache);
      return memoized;
    }

    // Expose `MapCache`.
    memoize.Cache = MapCache;

    /**
     * Creates a function that negates the result of the predicate `func`. The
     * `func` predicate is invoked with the `this` binding and arguments of the
     * created function.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Function
     * @param {Function} predicate The predicate to negate.
     * @returns {Function} Returns the new negated function.
     * @example
     *
     * function isEven(n) {
     *   return n % 2 == 0;
     * }
     *
     * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
     * // => [1, 3, 5]
     */
    function negate(predicate) {
      if (typeof predicate != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      return function() {
        var args = arguments;
        switch (args.length) {
          case 0: return !predicate.call(this);
          case 1: return !predicate.call(this, args[0]);
          case 2: return !predicate.call(this, args[0], args[1]);
          case 3: return !predicate.call(this, args[0], args[1], args[2]);
        }
        return !predicate.apply(this, args);
      };
    }

    /**
     * Creates a function that is restricted to invoking `func` once. Repeat calls
     * to the function return the value of the first invocation. The `func` is
     * invoked with the `this` binding and arguments of the created function.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to restrict.
     * @returns {Function} Returns the new restricted function.
     * @example
     *
     * var initialize = _.once(createApplication);
     * initialize();
     * initialize();
     * // => `createApplication` is invoked once
     */
    function once(func) {
      return before(2, func);
    }

    /**
     * Creates a function that invokes `func` with its arguments transformed.
     *
     * @static
     * @since 4.0.0
     * @memberOf _
     * @category Function
     * @param {Function} func The function to wrap.
     * @param {...(Function|Function[])} [transforms=[_.identity]]
     *  The argument transforms.
     * @returns {Function} Returns the new function.
     * @example
     *
     * function doubled(n) {
     *   return n * 2;
     * }
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * var func = _.overArgs(function(x, y) {
     *   return [x, y];
     * }, [square, doubled]);
     *
     * func(9, 3);
     * // => [81, 6]
     *
     * func(10, 5);
     * // => [100, 10]
     */
    var overArgs = castRest(function(func, transforms) {
      transforms = (transforms.length == 1 && isArray(transforms[0]))
        ? arrayMap(transforms[0], baseUnary(getIteratee()))
        : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));

      var funcsLength = transforms.length;
      return baseRest(function(args) {
        var index = -1,
            length = nativeMin(args.length, funcsLength);

        while (++index < length) {
          args[index] = transforms[index].call(this, args[index]);
        }
        return apply(func, this, args);
      });
    });

    /**
     * Creates a function that invokes `func` with `partials` prepended to the
     * arguments it receives. This method is like `_.bind` except it does **not**
     * alter the `this` binding.
     *
     * The `_.partial.placeholder` value, which defaults to `_` in monolithic
     * builds, may be used as a placeholder for partially applied arguments.
     *
     * **Note:** This method doesn't set the "length" property of partially
     * applied functions.
     *
     * @static
     * @memberOf _
     * @since 0.2.0
     * @category Function
     * @param {Function} func The function to partially apply arguments to.
     * @param {...*} [partials] The arguments to be partially applied.
     * @returns {Function} Returns the new partially applied function.
     * @example
     *
     * function greet(greeting, name) {
     *   return greeting + ' ' + name;
     * }
     *
     * var sayHelloTo = _.partial(greet, 'hello');
     * sayHelloTo('fred');
     * // => 'hello fred'
     *
     * // Partially applied with placeholders.
     * var greetFred = _.partial(greet, _, 'fred');
     * greetFred('hi');
     * // => 'hi fred'
     */
    var partial = baseRest(function(func, partials) {
      var holders = replaceHolders(partials, getHolder(partial));
      return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
    });

    /**
     * This method is like `_.partial` except that partially applied arguments
     * are appended to the arguments it receives.
     *
     * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
     * builds, may be used as a placeholder for partially applied arguments.
     *
     * **Note:** This method doesn't set the "length" property of partially
     * applied functions.
     *
     * @static
     * @memberOf _
     * @since 1.0.0
     * @category Function
     * @param {Function} func The function to partially apply arguments to.
     * @param {...*} [partials] The arguments to be partially applied.
     * @returns {Function} Returns the new partially applied function.
     * @example
     *
     * function greet(greeting, name) {
     *   return greeting + ' ' + name;
     * }
     *
     * var greetFred = _.partialRight(greet, 'fred');
     * greetFred('hi');
     * // => 'hi fred'
     *
     * // Partially applied with placeholders.
     * var sayHelloTo = _.partialRight(greet, 'hello', _);
     * sayHelloTo('fred');
     * // => 'hello fred'
     */
    var partialRight = baseRest(function(func, partials) {
      var holders = replaceHolders(partials, getHolder(partialRight));
      return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
    });

    /**
     * Creates a function that invokes `func` with arguments arranged according
     * to the specified `indexes` where the argument value at the first index is
     * provided as the first argument, the argument value at the second index is
     * provided as the second argument, and so on.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Function
     * @param {Function} func The function to rearrange arguments for.
     * @param {...(number|number[])} indexes The arranged argument indexes.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var rearged = _.rearg(function(a, b, c) {
     *   return [a, b, c];
     * }, [2, 0, 1]);
     *
     * rearged('b', 'c', 'a')
     * // => ['a', 'b', 'c']
     */
    var rearg = flatRest(function(func, indexes) {
      return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
    });

    /**
     * Creates a function that invokes `func` with the `this` binding of the
     * created function and arguments from `start` and beyond provided as
     * an array.
     *
     * **Note:** This method is based on the
     * [rest parameter](https://mdn.io/rest_parameters).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Function
     * @param {Function} func The function to apply a rest parameter to.
     * @param {number} [start=func.length-1] The start position of the rest parameter.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var say = _.rest(function(what, names) {
     *   return what + ' ' + _.initial(names).join(', ') +
     *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
     * });
     *
     * say('hello', 'fred', 'barney', 'pebbles');
     * // => 'hello fred, barney, & pebbles'
     */
    function rest(func, start) {
      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      start = start === undefined ? start : toInteger(start);
      return baseRest(func, start);
    }

    /**
     * Creates a function that invokes `func` with the `this` binding of the
     * create function and an array of arguments much like
     * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
     *
     * **Note:** This method is based on the
     * [spread operator](https://mdn.io/spread_operator).
     *
     * @static
     * @memberOf _
     * @since 3.2.0
     * @category Function
     * @param {Function} func The function to spread arguments over.
     * @param {number} [start=0] The start position of the spread.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var say = _.spread(function(who, what) {
     *   return who + ' says ' + what;
     * });
     *
     * say(['fred', 'hello']);
     * // => 'fred says hello'
     *
     * var numbers = Promise.all([
     *   Promise.resolve(40),
     *   Promise.resolve(36)
     * ]);
     *
     * numbers.then(_.spread(function(x, y) {
     *   return x + y;
     * }));
     * // => a Promise of 76
     */
    function spread(func, start) {
      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      start = start == null ? 0 : nativeMax(toInteger(start), 0);
      return baseRest(function(args) {
        var array = args[start],
            otherArgs = castSlice(args, 0, start);

        if (array) {
          arrayPush(otherArgs, array);
        }
        return apply(func, this, otherArgs);
      });
    }

    /**
     * Creates a throttled function that only invokes `func` at most once per
     * every `wait` milliseconds. The throttled function comes with a `cancel`
     * method to cancel delayed `func` invocations and a `flush` method to
     * immediately invoke them. Provide `options` to indicate whether `func`
     * should be invoked on the leading and/or trailing edge of the `wait`
     * timeout. The `func` is invoked with the last arguments provided to the
     * throttled function. Subsequent calls to the throttled function return the
     * result of the last `func` invocation.
     *
     * **Note:** If `leading` and `trailing` options are `true`, `func` is
     * invoked on the trailing edge of the timeout only if the throttled function
     * is invoked more than once during the `wait` timeout.
     *
     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
     *
     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
     * for details over the differences between `_.throttle` and `_.debounce`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {Function} func The function to throttle.
     * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
     * @param {Object} [options={}] The options object.
     * @param {boolean} [options.leading=true]
     *  Specify invoking on the leading edge of the timeout.
     * @param {boolean} [options.trailing=true]
     *  Specify invoking on the trailing edge of the timeout.
     * @returns {Function} Returns the new throttled function.
     * @example
     *
     * // Avoid excessively updating the position while scrolling.
     * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
     *
     * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
     * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
     * jQuery(element).on('click', throttled);
     *
     * // Cancel the trailing throttled invocation.
     * jQuery(window).on('popstate', throttled.cancel);
     */
    function throttle(func, wait, options) {
      var leading = true,
          trailing = true;

      if (typeof func != 'function') {
        throw new TypeError(FUNC_ERROR_TEXT);
      }
      if (isObject(options)) {
        leading = 'leading' in options ? !!options.leading : leading;
        trailing = 'trailing' in options ? !!options.trailing : trailing;
      }
      return debounce(func, wait, {
        'leading': leading,
        'maxWait': wait,
        'trailing': trailing
      });
    }

    /**
     * Creates a function that accepts up to one argument, ignoring any
     * additional arguments.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Function
     * @param {Function} func The function to cap arguments for.
     * @returns {Function} Returns the new capped function.
     * @example
     *
     * _.map(['6', '8', '10'], _.unary(parseInt));
     * // => [6, 8, 10]
     */
    function unary(func) {
      return ary(func, 1);
    }

    /**
     * Creates a function that provides `value` to `wrapper` as its first
     * argument. Any additional arguments provided to the function are appended
     * to those provided to the `wrapper`. The wrapper is invoked with the `this`
     * binding of the created function.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Function
     * @param {*} value The value to wrap.
     * @param {Function} [wrapper=identity] The wrapper function.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var p = _.wrap(_.escape, function(func, text) {
     *   return '<p>' + func(text) + '</p>';
     * });
     *
     * p('fred, barney, & pebbles');
     * // => '<p>fred, barney, &amp; pebbles</p>'
     */
    function wrap(value, wrapper) {
      return partial(castFunction(wrapper), value);
    }

    /*------------------------------------------------------------------------*/

    /**
     * Casts `value` as an array if it's not one.
     *
     * @static
     * @memberOf _
     * @since 4.4.0
     * @category Lang
     * @param {*} value The value to inspect.
     * @returns {Array} Returns the cast array.
     * @example
     *
     * _.castArray(1);
     * // => [1]
     *
     * _.castArray({ 'a': 1 });
     * // => [{ 'a': 1 }]
     *
     * _.castArray('abc');
     * // => ['abc']
     *
     * _.castArray(null);
     * // => [null]
     *
     * _.castArray(undefined);
     * // => [undefined]
     *
     * _.castArray();
     * // => []
     *
     * var array = [1, 2, 3];
     * console.log(_.castArray(array) === array);
     * // => true
     */
    function castArray() {
      if (!arguments.length) {
        return [];
      }
      var value = arguments[0];
      return isArray(value) ? value : [value];
    }

    /**
     * Creates a shallow clone of `value`.
     *
     * **Note:** This method is loosely based on the
     * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
     * and supports cloning arrays, array buffers, booleans, date objects, maps,
     * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
     * arrays. The own enumerable properties of `arguments` objects are cloned
     * as plain objects. An empty object is returned for uncloneable values such
     * as error objects, functions, DOM nodes, and WeakMaps.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to clone.
     * @returns {*} Returns the cloned value.
     * @see _.cloneDeep
     * @example
     *
     * var objects = [{ 'a': 1 }, { 'b': 2 }];
     *
     * var shallow = _.clone(objects);
     * console.log(shallow[0] === objects[0]);
     * // => true
     */
    function clone(value) {
      return baseClone(value, CLONE_SYMBOLS_FLAG);
    }

    /**
     * This method is like `_.clone` except that it accepts `customizer` which
     * is invoked to produce the cloned value. If `customizer` returns `undefined`,
     * cloning is handled by the method instead. The `customizer` is invoked with
     * up to four arguments; (value [, index|key, object, stack]).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to clone.
     * @param {Function} [customizer] The function to customize cloning.
     * @returns {*} Returns the cloned value.
     * @see _.cloneDeepWith
     * @example
     *
     * function customizer(value) {
     *   if (_.isElement(value)) {
     *     return value.cloneNode(false);
     *   }
     * }
     *
     * var el = _.cloneWith(document.body, customizer);
     *
     * console.log(el === document.body);
     * // => false
     * console.log(el.nodeName);
     * // => 'BODY'
     * console.log(el.childNodes.length);
     * // => 0
     */
    function cloneWith(value, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
    }

    /**
     * This method is like `_.clone` except that it recursively clones `value`.
     *
     * @static
     * @memberOf _
     * @since 1.0.0
     * @category Lang
     * @param {*} value The value to recursively clone.
     * @returns {*} Returns the deep cloned value.
     * @see _.clone
     * @example
     *
     * var objects = [{ 'a': 1 }, { 'b': 2 }];
     *
     * var deep = _.cloneDeep(objects);
     * console.log(deep[0] === objects[0]);
     * // => false
     */
    function cloneDeep(value) {
      return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
    }

    /**
     * This method is like `_.cloneWith` except that it recursively clones `value`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to recursively clone.
     * @param {Function} [customizer] The function to customize cloning.
     * @returns {*} Returns the deep cloned value.
     * @see _.cloneWith
     * @example
     *
     * function customizer(value) {
     *   if (_.isElement(value)) {
     *     return value.cloneNode(true);
     *   }
     * }
     *
     * var el = _.cloneDeepWith(document.body, customizer);
     *
     * console.log(el === document.body);
     * // => false
     * console.log(el.nodeName);
     * // => 'BODY'
     * console.log(el.childNodes.length);
     * // => 20
     */
    function cloneDeepWith(value, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
    }

    /**
     * Checks if `object` conforms to `source` by invoking the predicate
     * properties of `source` with the corresponding property values of `object`.
     *
     * **Note:** This method is equivalent to `_.conforms` when `source` is
     * partially applied.
     *
     * @static
     * @memberOf _
     * @since 4.14.0
     * @category Lang
     * @param {Object} object The object to inspect.
     * @param {Object} source The object of property predicates to conform to.
     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
     * @example
     *
     * var object = { 'a': 1, 'b': 2 };
     *
     * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
     * // => true
     *
     * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
     * // => false
     */
    function conformsTo(object, source) {
      return source == null || baseConformsTo(object, source, keys(source));
    }

    /**
     * Performs a
     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
     * comparison between two values to determine if they are equivalent.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     * @example
     *
     * var object = { 'a': 1 };
     * var other = { 'a': 1 };
     *
     * _.eq(object, object);
     * // => true
     *
     * _.eq(object, other);
     * // => false
     *
     * _.eq('a', 'a');
     * // => true
     *
     * _.eq('a', Object('a'));
     * // => false
     *
     * _.eq(NaN, NaN);
     * // => true
     */
    function eq(value, other) {
      return value === other || (value !== value && other !== other);
    }

    /**
     * Checks if `value` is greater than `other`.
     *
     * @static
     * @memberOf _
     * @since 3.9.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is greater than `other`,
     *  else `false`.
     * @see _.lt
     * @example
     *
     * _.gt(3, 1);
     * // => true
     *
     * _.gt(3, 3);
     * // => false
     *
     * _.gt(1, 3);
     * // => false
     */
    var gt = createRelationalOperation(baseGt);

    /**
     * Checks if `value` is greater than or equal to `other`.
     *
     * @static
     * @memberOf _
     * @since 3.9.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is greater than or equal to
     *  `other`, else `false`.
     * @see _.lte
     * @example
     *
     * _.gte(3, 1);
     * // => true
     *
     * _.gte(3, 3);
     * // => true
     *
     * _.gte(1, 3);
     * // => false
     */
    var gte = createRelationalOperation(function(value, other) {
      return value >= other;
    });

    /**
     * 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
     */
    var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
      return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
        !propertyIsEnumerable.call(value, 'callee');
    };

    /**
     * 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 classified as an `ArrayBuffer` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
     * @example
     *
     * _.isArrayBuffer(new ArrayBuffer(2));
     * // => true
     *
     * _.isArrayBuffer(new Array(2));
     * // => false
     */
    var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;

    /**
     * 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 boolean primitive or object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
     * @example
     *
     * _.isBoolean(false);
     * // => true
     *
     * _.isBoolean(null);
     * // => false
     */
    function isBoolean(value) {
      return value === true || value === false ||
        (isObjectLike(value) && baseGetTag(value) == boolTag);
    }

    /**
     * Checks if `value` is a buffer.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
     * @example
     *
     * _.isBuffer(new Buffer(2));
     * // => true
     *
     * _.isBuffer(new Uint8Array(2));
     * // => false
     */
    var isBuffer = nativeIsBuffer || stubFalse;

    /**
     * Checks if `value` is classified as a `Date` object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
     * @example
     *
     * _.isDate(new Date);
     * // => true
     *
     * _.isDate('Mon April 23 2012');
     * // => false
     */
    var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;

    /**
     * Checks if `value` is likely a DOM element.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
     * @example
     *
     * _.isElement(document.body);
     * // => true
     *
     * _.isElement('<body>');
     * // => false
     */
    function isElement(value) {
      return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
    }

    /**
     * Checks if `value` is an empty object, collection, map, or set.
     *
     * Objects are considered empty if they have no own enumerable string keyed
     * properties.
     *
     * Array-like values such as `arguments` objects, arrays, buffers, strings, or
     * jQuery-like collections are considered empty if they have a `length` of `0`.
     * Similarly, maps and sets are considered empty if they have a `size` of `0`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is empty, else `false`.
     * @example
     *
     * _.isEmpty(null);
     * // => true
     *
     * _.isEmpty(true);
     * // => true
     *
     * _.isEmpty(1);
     * // => true
     *
     * _.isEmpty([1, 2, 3]);
     * // => false
     *
     * _.isEmpty({ 'a': 1 });
     * // => false
     */
    function isEmpty(value) {
      if (value == null) {
        return true;
      }
      if (isArrayLike(value) &&
          (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
            isBuffer(value) || isTypedArray(value) || isArguments(value))) {
        return !value.length;
      }
      var tag = getTag(value);
      if (tag == mapTag || tag == setTag) {
        return !value.size;
      }
      if (isPrototype(value)) {
        return !baseKeys(value).length;
      }
      for (var key in value) {
        if (hasOwnProperty.call(value, key)) {
          return false;
        }
      }
      return true;
    }

    /**
     * Performs a deep comparison between two values to determine if they are
     * equivalent.
     *
     * **Note:** This method supports comparing arrays, array buffers, booleans,
     * date objects, error objects, maps, numbers, `Object` objects, regexes,
     * sets, strings, symbols, and typed arrays. `Object` objects are compared
     * by their own, not inherited, enumerable properties. Functions and DOM
     * nodes are compared by strict equality, i.e. `===`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     * @example
     *
     * var object = { 'a': 1 };
     * var other = { 'a': 1 };
     *
     * _.isEqual(object, other);
     * // => true
     *
     * object === other;
     * // => false
     */
    function isEqual(value, other) {
      return baseIsEqual(value, other);
    }

    /**
     * This method is like `_.isEqual` except that it accepts `customizer` which
     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
     * are handled by the method instead. The `customizer` is invoked with up to
     * six arguments: (objValue, othValue [, index|key, object, other, stack]).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @param {Function} [customizer] The function to customize comparisons.
     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
     * @example
     *
     * function isGreeting(value) {
     *   return /^h(?:i|ello)$/.test(value);
     * }
     *
     * function customizer(objValue, othValue) {
     *   if (isGreeting(objValue) && isGreeting(othValue)) {
     *     return true;
     *   }
     * }
     *
     * var array = ['hello', 'goodbye'];
     * var other = ['hi', 'goodbye'];
     *
     * _.isEqualWith(array, other, customizer);
     * // => true
     */
    function isEqualWith(value, other, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      var result = customizer ? customizer(value, other) : undefined;
      return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
    }

    /**
     * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
     * `SyntaxError`, `TypeError`, or `URIError` object.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
     * @example
     *
     * _.isError(new Error);
     * // => true
     *
     * _.isError(Error);
     * // => false
     */
    function isError(value) {
      if (!isObjectLike(value)) {
        return false;
      }
      var tag = baseGetTag(value);
      return tag == errorTag || tag == domExcTag ||
        (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
    }

    /**
     * Checks if `value` is a finite primitive number.
     *
     * **Note:** This method is based on
     * [`Number.isFinite`](https://mdn.io/Number/isFinite).
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
     * @example
     *
     * _.isFinite(3);
     * // => true
     *
     * _.isFinite(Number.MIN_VALUE);
     * // => true
     *
     * _.isFinite(Infinity);
     * // => false
     *
     * _.isFinite('3');
     * // => false
     */
    function isFinite(value) {
      return typeof value == 'number' && nativeIsFinite(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) {
      if (!isObject(value)) {
        return false;
      }
      // The use of `Object#toString` avoids issues with the `typeof` operator
      // in Safari 9 which returns 'object' for typed arrays and other constructors.
      var tag = baseGetTag(value);
      return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
    }

    /**
     * Checks if `value` is an integer.
     *
     * **Note:** This method is based on
     * [`Number.isInteger`](https://mdn.io/Number/isInteger).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
     * @example
     *
     * _.isInteger(3);
     * // => true
     *
     * _.isInteger(Number.MIN_VALUE);
     * // => false
     *
     * _.isInteger(Infinity);
     * // => false
     *
     * _.isInteger('3');
     * // => false
     */
    function isInteger(value) {
      return typeof value == 'number' && value == toInteger(value);
    }

    /**
     * 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 != null && (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 != null && typeof value == 'object';
    }

    /**
     * Checks if `value` is classified as a `Map` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
     * @example
     *
     * _.isMap(new Map);
     * // => true
     *
     * _.isMap(new WeakMap);
     * // => false
     */
    var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;

    /**
     * Performs a partial deep comparison between `object` and `source` to
     * determine if `object` contains equivalent property values.
     *
     * **Note:** This method is equivalent to `_.matches` when `source` is
     * partially applied.
     *
     * Partial comparisons will match empty array and empty object `source`
     * values against any array or object value, respectively. See `_.isEqual`
     * for a list of supported value comparisons.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {Object} object The object to inspect.
     * @param {Object} source The object of property values to match.
     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
     * @example
     *
     * var object = { 'a': 1, 'b': 2 };
     *
     * _.isMatch(object, { 'b': 2 });
     * // => true
     *
     * _.isMatch(object, { 'b': 1 });
     * // => false
     */
    function isMatch(object, source) {
      return object === source || baseIsMatch(object, source, getMatchData(source));
    }

    /**
     * This method is like `_.isMatch` except that it accepts `customizer` which
     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
     * are handled by the method instead. The `customizer` is invoked with five
     * arguments: (objValue, srcValue, index|key, object, source).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {Object} object The object to inspect.
     * @param {Object} source The object of property values to match.
     * @param {Function} [customizer] The function to customize comparisons.
     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
     * @example
     *
     * function isGreeting(value) {
     *   return /^h(?:i|ello)$/.test(value);
     * }
     *
     * function customizer(objValue, srcValue) {
     *   if (isGreeting(objValue) && isGreeting(srcValue)) {
     *     return true;
     *   }
     * }
     *
     * var object = { 'greeting': 'hello' };
     * var source = { 'greeting': 'hi' };
     *
     * _.isMatchWith(object, source, customizer);
     * // => true
     */
    function isMatchWith(object, source, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      return baseIsMatch(object, source, getMatchData(source), customizer);
    }

    /**
     * Checks if `value` is `NaN`.
     *
     * **Note:** This method is based on
     * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
     * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
     * `undefined` and other non-number values.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
     * @example
     *
     * _.isNaN(NaN);
     * // => true
     *
     * _.isNaN(new Number(NaN));
     * // => true
     *
     * isNaN(undefined);
     * // => true
     *
     * _.isNaN(undefined);
     * // => false
     */
    function isNaN(value) {
      // An `NaN` primitive is the only value that is not equal to itself.
      // Perform the `toStringTag` check first to avoid errors with some
      // ActiveX objects in IE.
      return isNumber(value) && value != +value;
    }

    /**
     * Checks if `value` is a pristine native function.
     *
     * **Note:** This method can't reliably detect native functions in the presence
     * of the core-js package because core-js circumvents this kind of detection.
     * Despite multiple requests, the core-js maintainer has made it clear: any
     * attempt to fix the detection will be obstructed. As a result, we're left
     * with little choice but to throw an error. Unfortunately, this also affects
     * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
     * which rely on core-js.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a native function,
     *  else `false`.
     * @example
     *
     * _.isNative(Array.prototype.push);
     * // => true
     *
     * _.isNative(_);
     * // => false
     */
    function isNative(value) {
      if (isMaskable(value)) {
        throw new Error(CORE_ERROR_TEXT);
      }
      return baseIsNative(value);
    }

    /**
     * Checks if `value` is `null`.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
     * @example
     *
     * _.isNull(null);
     * // => true
     *
     * _.isNull(void 0);
     * // => false
     */
    function isNull(value) {
      return value === null;
    }

    /**
     * Checks if `value` is `null` or `undefined`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
     * @example
     *
     * _.isNil(null);
     * // => true
     *
     * _.isNil(void 0);
     * // => true
     *
     * _.isNil(NaN);
     * // => false
     */
    function isNil(value) {
      return value == null;
    }

    /**
     * Checks if `value` is classified as a `Number` primitive or object.
     *
     * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
     * classified as numbers, use the `_.isFinite` method.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a number, else `false`.
     * @example
     *
     * _.isNumber(3);
     * // => true
     *
     * _.isNumber(Number.MIN_VALUE);
     * // => true
     *
     * _.isNumber(Infinity);
     * // => true
     *
     * _.isNumber('3');
     * // => false
     */
    function isNumber(value) {
      return typeof value == 'number' ||
        (isObjectLike(value) && baseGetTag(value) == numberTag);
    }

    /**
     * Checks if `value` is a plain object, that is, an object created by the
     * `Object` constructor or one with a `[[Prototype]]` of `null`.
     *
     * @static
     * @memberOf _
     * @since 0.8.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     * }
     *
     * _.isPlainObject(new Foo);
     * // => false
     *
     * _.isPlainObject([1, 2, 3]);
     * // => false
     *
     * _.isPlainObject({ 'x': 0, 'y': 0 });
     * // => true
     *
     * _.isPlainObject(Object.create(null));
     * // => true
     */
    function isPlainObject(value) {
      if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
        return false;
      }
      var proto = getPrototype(value);
      if (proto === null) {
        return true;
      }
      var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
      return typeof Ctor == 'function' && Ctor instanceof Ctor &&
        funcToString.call(Ctor) == objectCtorString;
    }

    /**
     * Checks if `value` is classified as a `RegExp` object.
     *
     * @static
     * @memberOf _
     * @since 0.1.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
     * @example
     *
     * _.isRegExp(/abc/);
     * // => true
     *
     * _.isRegExp('/abc/');
     * // => false
     */
    var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;

    /**
     * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
     * double precision number which isn't the result of a rounded unsafe integer.
     *
     * **Note:** This method is based on
     * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
     * @example
     *
     * _.isSafeInteger(3);
     * // => true
     *
     * _.isSafeInteger(Number.MIN_VALUE);
     * // => false
     *
     * _.isSafeInteger(Infinity);
     * // => false
     *
     * _.isSafeInteger('3');
     * // => false
     */
    function isSafeInteger(value) {
      return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
    }

    /**
     * Checks if `value` is classified as a `Set` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
     * @example
     *
     * _.isSet(new Set);
     * // => true
     *
     * _.isSet(new WeakSet);
     * // => false
     */
    var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;

    /**
     * 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) && baseGetTag(value) == stringTag);
    }

    /**
     * Checks if `value` is classified as a `Symbol` primitive or object.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
     * @example
     *
     * _.isSymbol(Symbol.iterator);
     * // => true
     *
     * _.isSymbol('abc');
     * // => false
     */
    function isSymbol(value) {
      return typeof value == 'symbol' ||
        (isObjectLike(value) && baseGetTag(value) == symbolTag);
    }

    /**
     * Checks if `value` is classified as a typed array.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
     * @example
     *
     * _.isTypedArray(new Uint8Array);
     * // => true
     *
     * _.isTypedArray([]);
     * // => false
     */
    var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;

    /**
     * Checks if `value` is `undefined`.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
     * @example
     *
     * _.isUndefined(void 0);
     * // => true
     *
     * _.isUndefined(null);
     * // => false
     */
    function isUndefined(value) {
      return value === undefined;
    }

    /**
     * Checks if `value` is classified as a `WeakMap` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
     * @example
     *
     * _.isWeakMap(new WeakMap);
     * // => true
     *
     * _.isWeakMap(new Map);
     * // => false
     */
    function isWeakMap(value) {
      return isObjectLike(value) && getTag(value) == weakMapTag;
    }

    /**
     * Checks if `value` is classified as a `WeakSet` object.
     *
     * @static
     * @memberOf _
     * @since 4.3.0
     * @category Lang
     * @param {*} value The value to check.
     * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
     * @example
     *
     * _.isWeakSet(new WeakSet);
     * // => true
     *
     * _.isWeakSet(new Set);
     * // => false
     */
    function isWeakSet(value) {
      return isObjectLike(value) && baseGetTag(value) == weakSetTag;
    }

    /**
     * Checks if `value` is less than `other`.
     *
     * @static
     * @memberOf _
     * @since 3.9.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is less than `other`,
     *  else `false`.
     * @see _.gt
     * @example
     *
     * _.lt(1, 3);
     * // => true
     *
     * _.lt(3, 3);
     * // => false
     *
     * _.lt(3, 1);
     * // => false
     */
    var lt = createRelationalOperation(baseLt);

    /**
     * Checks if `value` is less than or equal to `other`.
     *
     * @static
     * @memberOf _
     * @since 3.9.0
     * @category Lang
     * @param {*} value The value to compare.
     * @param {*} other The other value to compare.
     * @returns {boolean} Returns `true` if `value` is less than or equal to
     *  `other`, else `false`.
     * @see _.gte
     * @example
     *
     * _.lte(1, 3);
     * // => true
     *
     * _.lte(3, 3);
     * // => true
     *
     * _.lte(3, 1);
     * // => false
     */
    var lte = createRelationalOperation(function(value, other) {
      return value <= other;
    });

    /**
     * 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 (symIterator && value[symIterator]) {
        return iteratorToArray(value[symIterator]());
      }
      var tag = getTag(value),
          func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);

      return func(value);
    }

    /**
     * Converts `value` to a finite number.
     *
     * @static
     * @memberOf _
     * @since 4.12.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {number} Returns the converted number.
     * @example
     *
     * _.toFinite(3.2);
     * // => 3.2
     *
     * _.toFinite(Number.MIN_VALUE);
     * // => 5e-324
     *
     * _.toFinite(Infinity);
     * // => 1.7976931348623157e+308
     *
     * _.toFinite('3.2');
     * // => 3.2
     */
    function toFinite(value) {
      if (!value) {
        return value === 0 ? value : 0;
      }
      value = toNumber(value);
      if (value === INFINITY || value === -INFINITY) {
        var sign = (value < 0 ? -1 : 1);
        return sign * MAX_INTEGER;
      }
      return value === value ? value : 0;
    }

    /**
     * Converts `value` to an integer.
     *
     * **Note:** This method is loosely based on
     * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {number} Returns the converted integer.
     * @example
     *
     * _.toInteger(3.2);
     * // => 3
     *
     * _.toInteger(Number.MIN_VALUE);
     * // => 0
     *
     * _.toInteger(Infinity);
     * // => 1.7976931348623157e+308
     *
     * _.toInteger('3.2');
     * // => 3
     */
    function toInteger(value) {
      var result = toFinite(value),
          remainder = result % 1;

      return result === result ? (remainder ? result - remainder : result) : 0;
    }

    /**
     * Converts `value` to an integer suitable for use as the length of an
     * array-like object.
     *
     * **Note:** This method is 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 convert.
     * @returns {number} Returns the converted integer.
     * @example
     *
     * _.toLength(3.2);
     * // => 3
     *
     * _.toLength(Number.MIN_VALUE);
     * // => 0
     *
     * _.toLength(Infinity);
     * // => 4294967295
     *
     * _.toLength('3.2');
     * // => 3
     */
    function toLength(value) {
      return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
    }

    /**
     * Converts `value` to a number.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to process.
     * @returns {number} Returns the number.
     * @example
     *
     * _.toNumber(3.2);
     * // => 3.2
     *
     * _.toNumber(Number.MIN_VALUE);
     * // => 5e-324
     *
     * _.toNumber(Infinity);
     * // => Infinity
     *
     * _.toNumber('3.2');
     * // => 3.2
     */
    function toNumber(value) {
      if (typeof value == 'number') {
        return value;
      }
      if (isSymbol(value)) {
        return NAN;
      }
      if (isObject(value)) {
        var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
        value = isObject(other) ? (other + '') : other;
      }
      if (typeof value != 'string') {
        return value === 0 ? value : +value;
      }
      value = baseTrim(value);
      var isBinary = reIsBinary.test(value);
      return (isBinary || reIsOctal.test(value))
        ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
        : (reIsBadHex.test(value) ? NAN : +value);
    }

    /**
     * Converts `value` to a plain object flattening inherited enumerable string
     * keyed properties of `value` to own properties of the plain object.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {Object} Returns the converted plain object.
     * @example
     *
     * function Foo() {
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.assign({ 'a': 1 }, new Foo);
     * // => { 'a': 1, 'b': 2 }
     *
     * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
     * // => { 'a': 1, 'b': 2, 'c': 3 }
     */
    function toPlainObject(value) {
      return copyObject(value, keysIn(value));
    }

    /**
     * Converts `value` to a safe integer. A safe integer can be compared and
     * represented correctly.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {number} Returns the converted integer.
     * @example
     *
     * _.toSafeInteger(3.2);
     * // => 3
     *
     * _.toSafeInteger(Number.MIN_VALUE);
     * // => 0
     *
     * _.toSafeInteger(Infinity);
     * // => 9007199254740991
     *
     * _.toSafeInteger('3.2');
     * // => 3
     */
    function toSafeInteger(value) {
      return value
        ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
        : (value === 0 ? value : 0);
    }

    /**
     * Converts `value` to a string. An empty string is returned for `null`
     * and `undefined` values. The sign of `-0` is preserved.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Lang
     * @param {*} value The value to convert.
     * @returns {string} Returns the converted string.
     * @example
     *
     * _.toString(null);
     * // => ''
     *
     * _.toString(-0);
     * // => '-0'
     *
     * _.toString([1, 2, 3]);
     * // => '1,2,3'
     */
    function toString(value) {
      return value == null ? '' : baseToString(value);
    }

    /*------------------------------------------------------------------------*/

    /**
     * Assigns own enumerable string keyed properties of source objects to the
     * destination object. Source objects are applied from left to right.
     * Subsequent sources overwrite property assignments of previous sources.
     *
     * **Note:** This method mutates `object` and is loosely based on
     * [`Object.assign`](https://mdn.io/Object/assign).
     *
     * @static
     * @memberOf _
     * @since 0.10.0
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} [sources] The source objects.
     * @returns {Object} Returns `object`.
     * @see _.assignIn
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     * }
     *
     * function Bar() {
     *   this.c = 3;
     * }
     *
     * Foo.prototype.b = 2;
     * Bar.prototype.d = 4;
     *
     * _.assign({ 'a': 0 }, new Foo, new Bar);
     * // => { 'a': 1, 'c': 3 }
     */
    var assign = createAssigner(function(object, source) {
      if (isPrototype(source) || isArrayLike(source)) {
        copyObject(source, keys(source), object);
        return;
      }
      for (var key in source) {
        if (hasOwnProperty.call(source, key)) {
          assignValue(object, key, source[key]);
        }
      }
    });

    /**
     * This method is like `_.assign` except that it iterates over own and
     * inherited source properties.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @alias extend
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} [sources] The source objects.
     * @returns {Object} Returns `object`.
     * @see _.assign
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     * }
     *
     * function Bar() {
     *   this.c = 3;
     * }
     *
     * Foo.prototype.b = 2;
     * Bar.prototype.d = 4;
     *
     * _.assignIn({ 'a': 0 }, new Foo, new Bar);
     * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
     */
    var assignIn = createAssigner(function(object, source) {
      copyObject(source, keysIn(source), object);
    });

    /**
     * This method is like `_.assignIn` except that it accepts `customizer`
     * which is invoked to produce the assigned values. If `customizer` returns
     * `undefined`, assignment is handled by the method instead. The `customizer`
     * is invoked with five arguments: (objValue, srcValue, key, object, source).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @alias extendWith
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} sources The source objects.
     * @param {Function} [customizer] The function to customize assigned values.
     * @returns {Object} Returns `object`.
     * @see _.assignWith
     * @example
     *
     * function customizer(objValue, srcValue) {
     *   return _.isUndefined(objValue) ? srcValue : objValue;
     * }
     *
     * var defaults = _.partialRight(_.assignInWith, customizer);
     *
     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
     * // => { 'a': 1, 'b': 2 }
     */
    var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
      copyObject(source, keysIn(source), object, customizer);
    });

    /**
     * This method is like `_.assign` except that it accepts `customizer`
     * which is invoked to produce the assigned values. If `customizer` returns
     * `undefined`, assignment is handled by the method instead. The `customizer`
     * is invoked with five arguments: (objValue, srcValue, key, object, source).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} sources The source objects.
     * @param {Function} [customizer] The function to customize assigned values.
     * @returns {Object} Returns `object`.
     * @see _.assignInWith
     * @example
     *
     * function customizer(objValue, srcValue) {
     *   return _.isUndefined(objValue) ? srcValue : objValue;
     * }
     *
     * var defaults = _.partialRight(_.assignWith, customizer);
     *
     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
     * // => { 'a': 1, 'b': 2 }
     */
    var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
      copyObject(source, keys(source), object, customizer);
    });

    /**
     * Creates an array of values corresponding to `paths` of `object`.
     *
     * @static
     * @memberOf _
     * @since 1.0.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {...(string|string[])} [paths] The property paths to pick.
     * @returns {Array} Returns the picked values.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
     *
     * _.at(object, ['a[0].b.c', 'a[1]']);
     * // => [3, 4]
     */
    var at = flatRest(baseAt);

    /**
     * Creates an object that inherits from the `prototype` object. If a
     * `properties` object is given, its own enumerable string keyed properties
     * are assigned to the created object.
     *
     * @static
     * @memberOf _
     * @since 2.3.0
     * @category Object
     * @param {Object} prototype The object to inherit from.
     * @param {Object} [properties] The properties to assign to the object.
     * @returns {Object} Returns the new object.
     * @example
     *
     * function Shape() {
     *   this.x = 0;
     *   this.y = 0;
     * }
     *
     * function Circle() {
     *   Shape.call(this);
     * }
     *
     * Circle.prototype = _.create(Shape.prototype, {
     *   'constructor': Circle
     * });
     *
     * var circle = new Circle;
     * circle instanceof Circle;
     * // => true
     *
     * circle instanceof Shape;
     * // => true
     */
    function create(prototype, properties) {
      var result = baseCreate(prototype);
      return properties == null ? result : baseAssign(result, properties);
    }

    /**
     * Assigns own and inherited enumerable string keyed properties of source
     * objects to the destination object for all destination properties that
     * resolve to `undefined`. Source objects are applied from left to right.
     * Once a property is set, additional values of the same property are ignored.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} [sources] The source objects.
     * @returns {Object} Returns `object`.
     * @see _.defaultsDeep
     * @example
     *
     * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
     * // => { 'a': 1, 'b': 2 }
     */
    var defaults = baseRest(function(object, sources) {
      object = Object(object);

      var index = -1;
      var length = sources.length;
      var guard = length > 2 ? sources[2] : undefined;

      if (guard && isIterateeCall(sources[0], sources[1], guard)) {
        length = 1;
      }

      while (++index < length) {
        var source = sources[index];
        var props = keysIn(source);
        var propsIndex = -1;
        var propsLength = props.length;

        while (++propsIndex < propsLength) {
          var key = props[propsIndex];
          var value = object[key];

          if (value === undefined ||
              (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {
            object[key] = source[key];
          }
        }
      }

      return object;
    });

    /**
     * This method is like `_.defaults` except that it recursively assigns
     * default properties.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 3.10.0
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} [sources] The source objects.
     * @returns {Object} Returns `object`.
     * @see _.defaults
     * @example
     *
     * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
     * // => { 'a': { 'b': 2, 'c': 3 } }
     */
    var defaultsDeep = baseRest(function(args) {
      args.push(undefined, customDefaultsMerge);
      return apply(mergeWith, undefined, args);
    });

    /**
     * This method is like `_.find` except that it returns the key of the first
     * element `predicate` returns truthy for instead of the element itself.
     *
     * @static
     * @memberOf _
     * @since 1.1.0
     * @category Object
     * @param {Object} object The object to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {string|undefined} Returns the key of the matched element,
     *  else `undefined`.
     * @example
     *
     * var users = {
     *   'barney':  { 'age': 36, 'active': true },
     *   'fred':    { 'age': 40, 'active': false },
     *   'pebbles': { 'age': 1,  'active': true }
     * };
     *
     * _.findKey(users, function(o) { return o.age < 40; });
     * // => 'barney' (iteration order is not guaranteed)
     *
     * // The `_.matches` iteratee shorthand.
     * _.findKey(users, { 'age': 1, 'active': true });
     * // => 'pebbles'
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.findKey(users, ['active', false]);
     * // => 'fred'
     *
     * // The `_.property` iteratee shorthand.
     * _.findKey(users, 'active');
     * // => 'barney'
     */
    function findKey(object, predicate) {
      return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
    }

    /**
     * This method is like `_.findKey` except that it iterates over elements of
     * a collection in the opposite order.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Object
     * @param {Object} object The object to inspect.
     * @param {Function} [predicate=_.identity] The function invoked per iteration.
     * @returns {string|undefined} Returns the key of the matched element,
     *  else `undefined`.
     * @example
     *
     * var users = {
     *   'barney':  { 'age': 36, 'active': true },
     *   'fred':    { 'age': 40, 'active': false },
     *   'pebbles': { 'age': 1,  'active': true }
     * };
     *
     * _.findLastKey(users, function(o) { return o.age < 40; });
     * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
     *
     * // The `_.matches` iteratee shorthand.
     * _.findLastKey(users, { 'age': 36, 'active': true });
     * // => 'barney'
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.findLastKey(users, ['active', false]);
     * // => 'fred'
     *
     * // The `_.property` iteratee shorthand.
     * _.findLastKey(users, 'active');
     * // => 'pebbles'
     */
    function findLastKey(object, predicate) {
      return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
    }

    /**
     * Iterates over own and inherited enumerable string keyed properties of an
     * object and invokes `iteratee` for each property. The iteratee is invoked
     * with three arguments: (value, key, object). Iteratee functions may exit
     * iteration early by explicitly returning `false`.
     *
     * @static
     * @memberOf _
     * @since 0.3.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns `object`.
     * @see _.forInRight
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.forIn(new Foo, function(value, key) {
     *   console.log(key);
     * });
     * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
     */
    function forIn(object, iteratee) {
      return object == null
        ? object
        : baseFor(object, getIteratee(iteratee, 3), keysIn);
    }

    /**
     * This method is like `_.forIn` except that it iterates over properties of
     * `object` in the opposite order.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns `object`.
     * @see _.forIn
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.forInRight(new Foo, function(value, key) {
     *   console.log(key);
     * });
     * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
     */
    function forInRight(object, iteratee) {
      return object == null
        ? object
        : baseForRight(object, getIteratee(iteratee, 3), keysIn);
    }

    /**
     * Iterates over own enumerable string keyed properties of an object and
     * invokes `iteratee` for each property. The iteratee is invoked with three
     * arguments: (value, key, object). Iteratee functions may exit iteration
     * early by explicitly returning `false`.
     *
     * @static
     * @memberOf _
     * @since 0.3.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns `object`.
     * @see _.forOwnRight
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.forOwn(new Foo, function(value, key) {
     *   console.log(key);
     * });
     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
     */
    function forOwn(object, iteratee) {
      return object && baseForOwn(object, getIteratee(iteratee, 3));
    }

    /**
     * This method is like `_.forOwn` except that it iterates over properties of
     * `object` in the opposite order.
     *
     * @static
     * @memberOf _
     * @since 2.0.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns `object`.
     * @see _.forOwn
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.forOwnRight(new Foo, function(value, key) {
     *   console.log(key);
     * });
     * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
     */
    function forOwnRight(object, iteratee) {
      return object && baseForOwnRight(object, getIteratee(iteratee, 3));
    }

    /**
     * Creates an array of function property names from own enumerable properties
     * of `object`.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The object to inspect.
     * @returns {Array} Returns the function names.
     * @see _.functionsIn
     * @example
     *
     * function Foo() {
     *   this.a = _.constant('a');
     *   this.b = _.constant('b');
     * }
     *
     * Foo.prototype.c = _.constant('c');
     *
     * _.functions(new Foo);
     * // => ['a', 'b']
     */
    function functions(object) {
      return object == null ? [] : baseFunctions(object, keys(object));
    }

    /**
     * Creates an array of function property names from own and inherited
     * enumerable properties of `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The object to inspect.
     * @returns {Array} Returns the function names.
     * @see _.functions
     * @example
     *
     * function Foo() {
     *   this.a = _.constant('a');
     *   this.b = _.constant('b');
     * }
     *
     * Foo.prototype.c = _.constant('c');
     *
     * _.functionsIn(new Foo);
     * // => ['a', 'b', 'c']
     */
    function functionsIn(object) {
      return object == null ? [] : baseFunctions(object, keysIn(object));
    }

    /**
     * Gets the value at `path` of `object`. If the resolved value is
     * `undefined`, the `defaultValue` is returned in its place.
     *
     * @static
     * @memberOf _
     * @since 3.7.0
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the property to get.
     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
     * @returns {*} Returns the resolved value.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
     *
     * _.get(object, 'a[0].b.c');
     * // => 3
     *
     * _.get(object, ['a', '0', 'b', 'c']);
     * // => 3
     *
     * _.get(object, 'a.b.c', 'default');
     * // => 'default'
     */
    function get(object, path, defaultValue) {
      var result = object == null ? undefined : baseGet(object, path);
      return result === undefined ? defaultValue : result;
    }

    /**
     * Checks if `path` is a direct property of `object`.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path to check.
     * @returns {boolean} Returns `true` if `path` exists, else `false`.
     * @example
     *
     * var object = { 'a': { 'b': 2 } };
     * var other = _.create({ 'a': _.create({ 'b': 2 }) });
     *
     * _.has(object, 'a');
     * // => true
     *
     * _.has(object, 'a.b');
     * // => true
     *
     * _.has(object, ['a', 'b']);
     * // => true
     *
     * _.has(other, 'a');
     * // => false
     */
    function has(object, path) {
      return object != null && hasPath(object, path, baseHas);
    }

    /**
     * Checks if `path` is a direct or inherited property of `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path to check.
     * @returns {boolean} Returns `true` if `path` exists, else `false`.
     * @example
     *
     * var object = _.create({ 'a': _.create({ 'b': 2 }) });
     *
     * _.hasIn(object, 'a');
     * // => true
     *
     * _.hasIn(object, 'a.b');
     * // => true
     *
     * _.hasIn(object, ['a', 'b']);
     * // => true
     *
     * _.hasIn(object, 'b');
     * // => false
     */
    function hasIn(object, path) {
      return object != null && hasPath(object, path, baseHasIn);
    }

    /**
     * Creates an object composed of the inverted keys and values of `object`.
     * If `object` contains duplicate values, subsequent values overwrite
     * property assignments of previous values.
     *
     * @static
     * @memberOf _
     * @since 0.7.0
     * @category Object
     * @param {Object} object The object to invert.
     * @returns {Object} Returns the new inverted object.
     * @example
     *
     * var object = { 'a': 1, 'b': 2, 'c': 1 };
     *
     * _.invert(object);
     * // => { '1': 'c', '2': 'b' }
     */
    var invert = createInverter(function(result, value, key) {
      if (value != null &&
          typeof value.toString != 'function') {
        value = nativeObjectToString.call(value);
      }

      result[value] = key;
    }, constant(identity));

    /**
     * This method is like `_.invert` except that the inverted object is generated
     * from the results of running each element of `object` thru `iteratee`. The
     * corresponding inverted value of each inverted key is an array of keys
     * responsible for generating the inverted value. The iteratee is invoked
     * with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.1.0
     * @category Object
     * @param {Object} object The object to invert.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {Object} Returns the new inverted object.
     * @example
     *
     * var object = { 'a': 1, 'b': 2, 'c': 1 };
     *
     * _.invertBy(object);
     * // => { '1': ['a', 'c'], '2': ['b'] }
     *
     * _.invertBy(object, function(value) {
     *   return 'group' + value;
     * });
     * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
     */
    var invertBy = createInverter(function(result, value, key) {
      if (value != null &&
          typeof value.toString != 'function') {
        value = nativeObjectToString.call(value);
      }

      if (hasOwnProperty.call(result, value)) {
        result[value].push(key);
      } else {
        result[value] = [key];
      }
    }, getIteratee);

    /**
     * Invokes the method at `path` of `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the method to invoke.
     * @param {...*} [args] The arguments to invoke the method with.
     * @returns {*} Returns the result of the invoked method.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
     *
     * _.invoke(object, 'a[0].b.c.slice', 1, 3);
     * // => [2, 3]
     */
    var invoke = baseRest(baseInvoke);

    /**
     * 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 and inherited enumerable property names of `object`.
     *
     * **Note:** Non-object values are coerced to objects.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @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;
     *
     * _.keysIn(new Foo);
     * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
     */
    function keysIn(object) {
      return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
    }

    /**
     * The opposite of `_.mapValues`; this method creates an object with the
     * same values as `object` and keys generated by running each own enumerable
     * string keyed property of `object` thru `iteratee`. The iteratee is invoked
     * with three arguments: (value, key, object).
     *
     * @static
     * @memberOf _
     * @since 3.8.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns the new mapped object.
     * @see _.mapValues
     * @example
     *
     * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
     *   return key + value;
     * });
     * // => { 'a1': 1, 'b2': 2 }
     */
    function mapKeys(object, iteratee) {
      var result = {};
      iteratee = getIteratee(iteratee, 3);

      baseForOwn(object, function(value, key, object) {
        baseAssignValue(result, iteratee(value, key, object), value);
      });
      return result;
    }

    /**
     * Creates an object with the same keys as `object` and values generated
     * by running each own enumerable string keyed property of `object` thru
     * `iteratee`. The iteratee is invoked with three arguments:
     * (value, key, object).
     *
     * @static
     * @memberOf _
     * @since 2.4.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Object} Returns the new mapped object.
     * @see _.mapKeys
     * @example
     *
     * var users = {
     *   'fred':    { 'user': 'fred',    'age': 40 },
     *   'pebbles': { 'user': 'pebbles', 'age': 1 }
     * };
     *
     * _.mapValues(users, function(o) { return o.age; });
     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
     *
     * // The `_.property` iteratee shorthand.
     * _.mapValues(users, 'age');
     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
     */
    function mapValues(object, iteratee) {
      var result = {};
      iteratee = getIteratee(iteratee, 3);

      baseForOwn(object, function(value, key, object) {
        baseAssignValue(result, key, iteratee(value, key, object));
      });
      return result;
    }

    /**
     * This method is like `_.assign` except that it recursively merges own and
     * inherited enumerable string keyed properties of source objects into the
     * destination object. Source properties that resolve to `undefined` are
     * skipped if a destination value exists. Array and plain object properties
     * are merged recursively. Other objects and value types are overridden by
     * assignment. Source objects are applied from left to right. Subsequent
     * sources overwrite property assignments of previous sources.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 0.5.0
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} [sources] The source objects.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var object = {
     *   'a': [{ 'b': 2 }, { 'd': 4 }]
     * };
     *
     * var other = {
     *   'a': [{ 'c': 3 }, { 'e': 5 }]
     * };
     *
     * _.merge(object, other);
     * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
     */
    var merge = createAssigner(function(object, source, srcIndex) {
      baseMerge(object, source, srcIndex);
    });

    /**
     * This method is like `_.merge` except that it accepts `customizer` which
     * is invoked to produce the merged values of the destination and source
     * properties. If `customizer` returns `undefined`, merging is handled by the
     * method instead. The `customizer` is invoked with six arguments:
     * (objValue, srcValue, key, object, source, stack).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The destination object.
     * @param {...Object} sources The source objects.
     * @param {Function} customizer The function to customize assigned values.
     * @returns {Object} Returns `object`.
     * @example
     *
     * function customizer(objValue, srcValue) {
     *   if (_.isArray(objValue)) {
     *     return objValue.concat(srcValue);
     *   }
     * }
     *
     * var object = { 'a': [1], 'b': [2] };
     * var other = { 'a': [3], 'b': [4] };
     *
     * _.mergeWith(object, other, customizer);
     * // => { 'a': [1, 3], 'b': [2, 4] }
     */
    var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
      baseMerge(object, source, srcIndex, customizer);
    });

    /**
     * The opposite of `_.pick`; this method creates an object composed of the
     * own and inherited enumerable property paths of `object` that are not omitted.
     *
     * **Note:** This method is considerably slower than `_.pick`.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The source object.
     * @param {...(string|string[])} [paths] The property paths to omit.
     * @returns {Object} Returns the new object.
     * @example
     *
     * var object = { 'a': 1, 'b': '2', 'c': 3 };
     *
     * _.omit(object, ['a', 'c']);
     * // => { 'b': '2' }
     */
    var omit = flatRest(function(object, paths) {
      var result = {};
      if (object == null) {
        return result;
      }
      var isDeep = false;
      paths = arrayMap(paths, function(path) {
        path = castPath(path, object);
        isDeep || (isDeep = path.length > 1);
        return path;
      });
      copyObject(object, getAllKeysIn(object), result);
      if (isDeep) {
        result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
      }
      var length = paths.length;
      while (length--) {
        baseUnset(result, paths[length]);
      }
      return result;
    });

    /**
     * The opposite of `_.pickBy`; this method creates an object composed of
     * the own and inherited enumerable string keyed properties of `object` that
     * `predicate` doesn't return truthy for. The predicate is invoked with two
     * arguments: (value, key).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The source object.
     * @param {Function} [predicate=_.identity] The function invoked per property.
     * @returns {Object} Returns the new object.
     * @example
     *
     * var object = { 'a': 1, 'b': '2', 'c': 3 };
     *
     * _.omitBy(object, _.isNumber);
     * // => { 'b': '2' }
     */
    function omitBy(object, predicate) {
      return pickBy(object, negate(getIteratee(predicate)));
    }

    /**
     * Creates an object composed of the picked `object` properties.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The source object.
     * @param {...(string|string[])} [paths] The property paths to pick.
     * @returns {Object} Returns the new object.
     * @example
     *
     * var object = { 'a': 1, 'b': '2', 'c': 3 };
     *
     * _.pick(object, ['a', 'c']);
     * // => { 'a': 1, 'c': 3 }
     */
    var pick = flatRest(function(object, paths) {
      return object == null ? {} : basePick(object, paths);
    });

    /**
     * Creates an object composed of the `object` properties `predicate` returns
     * truthy for. The predicate is invoked with two arguments: (value, key).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The source object.
     * @param {Function} [predicate=_.identity] The function invoked per property.
     * @returns {Object} Returns the new object.
     * @example
     *
     * var object = { 'a': 1, 'b': '2', 'c': 3 };
     *
     * _.pickBy(object, _.isNumber);
     * // => { 'a': 1, 'c': 3 }
     */
    function pickBy(object, predicate) {
      if (object == null) {
        return {};
      }
      var props = arrayMap(getAllKeysIn(object), function(prop) {
        return [prop];
      });
      predicate = getIteratee(predicate);
      return basePickBy(object, props, function(value, path) {
        return predicate(value, path[0]);
      });
    }

    /**
     * This method is like `_.get` except that if the resolved value is a
     * function it's invoked with the `this` binding of its parent object and
     * its result is returned.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Object
     * @param {Object} object The object to query.
     * @param {Array|string} path The path of the property to resolve.
     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
     * @returns {*} Returns the resolved value.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
     *
     * _.result(object, 'a[0].b.c1');
     * // => 3
     *
     * _.result(object, 'a[0].b.c2');
     * // => 4
     *
     * _.result(object, 'a[0].b.c3', 'default');
     * // => 'default'
     *
     * _.result(object, 'a[0].b.c3', _.constant('default'));
     * // => 'default'
     */
    function result(object, path, defaultValue) {
      path = castPath(path, object);

      var index = -1,
          length = path.length;

      // Ensure the loop is entered when path is empty.
      if (!length) {
        length = 1;
        object = undefined;
      }
      while (++index < length) {
        var value = object == null ? undefined : object[toKey(path[index])];
        if (value === undefined) {
          index = length;
          value = defaultValue;
        }
        object = isFunction(value) ? value.call(object) : value;
      }
      return object;
    }

    /**
     * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
     * it's created. Arrays are created for missing index properties while objects
     * are created for all other missing properties. Use `_.setWith` to customize
     * `path` creation.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 3.7.0
     * @category Object
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to set.
     * @param {*} value The value to set.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
     *
     * _.set(object, 'a[0].b.c', 4);
     * console.log(object.a[0].b.c);
     * // => 4
     *
     * _.set(object, ['x', '0', 'y', 'z'], 5);
     * console.log(object.x[0].y.z);
     * // => 5
     */
    function set(object, path, value) {
      return object == null ? object : baseSet(object, path, value);
    }

    /**
     * This method is like `_.set` except that it accepts `customizer` which is
     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
     * path creation is handled by the method instead. The `customizer` is invoked
     * with three arguments: (nsValue, key, nsObject).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to set.
     * @param {*} value The value to set.
     * @param {Function} [customizer] The function to customize assigned values.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var object = {};
     *
     * _.setWith(object, '[0][1]', 'a', Object);
     * // => { '0': { '1': 'a' } }
     */
    function setWith(object, path, value, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      return object == null ? object : baseSet(object, path, value, customizer);
    }

    /**
     * Creates an array of own enumerable string keyed-value pairs for `object`
     * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
     * entries are returned.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @alias entries
     * @category Object
     * @param {Object} object The object to query.
     * @returns {Array} Returns the key-value pairs.
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.toPairs(new Foo);
     * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
     */
    var toPairs = createToPairs(keys);

    /**
     * Creates an array of own and inherited enumerable string keyed-value pairs
     * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
     * or set, its entries are returned.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @alias entriesIn
     * @category Object
     * @param {Object} object The object to query.
     * @returns {Array} Returns the key-value pairs.
     * @example
     *
     * function Foo() {
     *   this.a = 1;
     *   this.b = 2;
     * }
     *
     * Foo.prototype.c = 3;
     *
     * _.toPairsIn(new Foo);
     * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
     */
    var toPairsIn = createToPairs(keysIn);

    /**
     * An alternative to `_.reduce`; this method transforms `object` to a new
     * `accumulator` object which is the result of running each of its own
     * enumerable string keyed properties thru `iteratee`, with each invocation
     * potentially mutating the `accumulator` object. If `accumulator` is not
     * provided, a new object with the same `[[Prototype]]` will be used. The
     * iteratee is invoked with four arguments: (accumulator, value, key, object).
     * Iteratee functions may exit iteration early by explicitly returning `false`.
     *
     * @static
     * @memberOf _
     * @since 1.3.0
     * @category Object
     * @param {Object} object The object to iterate over.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @param {*} [accumulator] The custom accumulator value.
     * @returns {*} Returns the accumulated value.
     * @example
     *
     * _.transform([2, 3, 4], function(result, n) {
     *   result.push(n *= n);
     *   return n % 2 == 0;
     * }, []);
     * // => [4, 9]
     *
     * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
     *   (result[value] || (result[value] = [])).push(key);
     * }, {});
     * // => { '1': ['a', 'c'], '2': ['b'] }
     */
    function transform(object, iteratee, accumulator) {
      var isArr = isArray(object),
          isArrLike = isArr || isBuffer(object) || isTypedArray(object);

      iteratee = getIteratee(iteratee, 4);
      if (accumulator == null) {
        var Ctor = object && object.constructor;
        if (isArrLike) {
          accumulator = isArr ? new Ctor : [];
        }
        else if (isObject(object)) {
          accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
        }
        else {
          accumulator = {};
        }
      }
      (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
        return iteratee(accumulator, value, index, object);
      });
      return accumulator;
    }

    /**
     * Removes the property at `path` of `object`.
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Object
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to unset.
     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 7 } }] };
     * _.unset(object, 'a[0].b.c');
     * // => true
     *
     * console.log(object);
     * // => { 'a': [{ 'b': {} }] };
     *
     * _.unset(object, ['a', '0', 'b', 'c']);
     * // => true
     *
     * console.log(object);
     * // => { 'a': [{ 'b': {} }] };
     */
    function unset(object, path) {
      return object == null ? true : baseUnset(object, path);
    }

    /**
     * This method is like `_.set` except that accepts `updater` to produce the
     * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
     * is invoked with one argument: (value).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.6.0
     * @category Object
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to set.
     * @param {Function} updater The function to produce the updated value.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
     *
     * _.update(object, 'a[0].b.c', function(n) { return n * n; });
     * console.log(object.a[0].b.c);
     * // => 9
     *
     * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
     * console.log(object.x[0].y.z);
     * // => 0
     */
    function update(object, path, updater) {
      return object == null ? object : baseUpdate(object, path, castFunction(updater));
    }

    /**
     * This method is like `_.update` except that it accepts `customizer` which is
     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
     * path creation is handled by the method instead. The `customizer` is invoked
     * with three arguments: (nsValue, key, nsObject).
     *
     * **Note:** This method mutates `object`.
     *
     * @static
     * @memberOf _
     * @since 4.6.0
     * @category Object
     * @param {Object} object The object to modify.
     * @param {Array|string} path The path of the property to set.
     * @param {Function} updater The function to produce the updated value.
     * @param {Function} [customizer] The function to customize assigned values.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var object = {};
     *
     * _.updateWith(object, '[0][1]', _.constant('a'), Object);
     * // => { '0': { '1': 'a' } }
     */
    function updateWith(object, path, updater, customizer) {
      customizer = typeof customizer == 'function' ? customizer : undefined;
      return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
    }

    /**
     * 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 == null ? [] : baseValues(object, keys(object));
    }

    /**
     * Creates an array of the own and inherited enumerable string keyed property
     * values of `object`.
     *
     * **Note:** Non-object values are coerced to objects.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @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;
     *
     * _.valuesIn(new Foo);
     * // => [1, 2, 3] (iteration order is not guaranteed)
     */
    function valuesIn(object) {
      return object == null ? [] : baseValues(object, keysIn(object));
    }

    /*------------------------------------------------------------------------*/

    /**
     * Clamps `number` within the inclusive `lower` and `upper` bounds.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Number
     * @param {number} number The number to clamp.
     * @param {number} [lower] The lower bound.
     * @param {number} upper The upper bound.
     * @returns {number} Returns the clamped number.
     * @example
     *
     * _.clamp(-10, -5, 5);
     * // => -5
     *
     * _.clamp(10, -5, 5);
     * // => 5
     */
    function clamp(number, lower, upper) {
      if (upper === undefined) {
        upper = lower;
        lower = undefined;
      }
      if (upper !== undefined) {
        upper = toNumber(upper);
        upper = upper === upper ? upper : 0;
      }
      if (lower !== undefined) {
        lower = toNumber(lower);
        lower = lower === lower ? lower : 0;
      }
      return baseClamp(toNumber(number), lower, upper);
    }

    /**
     * Checks if `n` is between `start` and up to, but not including, `end`. If
     * `end` is not specified, it's set to `start` with `start` then set to `0`.
     * If `start` is greater than `end` the params are swapped to support
     * negative ranges.
     *
     * @static
     * @memberOf _
     * @since 3.3.0
     * @category Number
     * @param {number} number The number to check.
     * @param {number} [start=0] The start of the range.
     * @param {number} end The end of the range.
     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
     * @see _.range, _.rangeRight
     * @example
     *
     * _.inRange(3, 2, 4);
     * // => true
     *
     * _.inRange(4, 8);
     * // => true
     *
     * _.inRange(4, 2);
     * // => false
     *
     * _.inRange(2, 2);
     * // => false
     *
     * _.inRange(1.2, 2);
     * // => true
     *
     * _.inRange(5.2, 4);
     * // => false
     *
     * _.inRange(-3, -2, -6);
     * // => true
     */
    function inRange(number, start, end) {
      start = toFinite(start);
      if (end === undefined) {
        end = start;
        start = 0;
      } else {
        end = toFinite(end);
      }
      number = toNumber(number);
      return baseInRange(number, start, end);
    }

    /**
     * Produces a random number between the inclusive `lower` and `upper` bounds.
     * If only one argument is provided a number between `0` and the given number
     * is returned. If `floating` is `true`, or either `lower` or `upper` are
     * floats, a floating-point number is returned instead of an integer.
     *
     * **Note:** JavaScript follows the IEEE-754 standard for resolving
     * floating-point values which can produce unexpected results.
     *
     * @static
     * @memberOf _
     * @since 0.7.0
     * @category Number
     * @param {number} [lower=0] The lower bound.
     * @param {number} [upper=1] The upper bound.
     * @param {boolean} [floating] Specify returning a floating-point number.
     * @returns {number} Returns the random number.
     * @example
     *
     * _.random(0, 5);
     * // => an integer between 0 and 5
     *
     * _.random(5);
     * // => also an integer between 0 and 5
     *
     * _.random(5, true);
     * // => a floating-point number between 0 and 5
     *
     * _.random(1.2, 5.2);
     * // => a floating-point number between 1.2 and 5.2
     */
    function random(lower, upper, floating) {
      if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
        upper = floating = undefined;
      }
      if (floating === undefined) {
        if (typeof upper == 'boolean') {
          floating = upper;
          upper = undefined;
        }
        else if (typeof lower == 'boolean') {
          floating = lower;
          lower = undefined;
        }
      }
      if (lower === undefined && upper === undefined) {
        lower = 0;
        upper = 1;
      }
      else {
        lower = toFinite(lower);
        if (upper === undefined) {
          upper = lower;
          lower = 0;
        } else {
          upper = toFinite(upper);
        }
      }
      if (lower > upper) {
        var temp = lower;
        lower = upper;
        upper = temp;
      }
      if (floating || lower % 1 || upper % 1) {
        var rand = nativeRandom();
        return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
      }
      return baseRandom(lower, upper);
    }

    /*------------------------------------------------------------------------*/

    /**
     * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the camel cased string.
     * @example
     *
     * _.camelCase('Foo Bar');
     * // => 'fooBar'
     *
     * _.camelCase('--foo-bar--');
     * // => 'fooBar'
     *
     * _.camelCase('__FOO_BAR__');
     * // => 'fooBar'
     */
    var camelCase = createCompounder(function(result, word, index) {
      word = word.toLowerCase();
      return result + (index ? capitalize(word) : word);
    });

    /**
     * Converts the first character of `string` to upper case and the remaining
     * to lower case.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to capitalize.
     * @returns {string} Returns the capitalized string.
     * @example
     *
     * _.capitalize('FRED');
     * // => 'Fred'
     */
    function capitalize(string) {
      return upperFirst(toString(string).toLowerCase());
    }

    /**
     * Deburrs `string` by converting
     * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
     * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
     * letters to basic Latin letters and removing
     * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to deburr.
     * @returns {string} Returns the deburred string.
     * @example
     *
     * _.deburr('déjà vu');
     * // => 'deja vu'
     */
    function deburr(string) {
      string = toString(string);
      return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
    }

    /**
     * Checks if `string` ends with the given target string.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to inspect.
     * @param {string} [target] The string to search for.
     * @param {number} [position=string.length] The position to search up to.
     * @returns {boolean} Returns `true` if `string` ends with `target`,
     *  else `false`.
     * @example
     *
     * _.endsWith('abc', 'c');
     * // => true
     *
     * _.endsWith('abc', 'b');
     * // => false
     *
     * _.endsWith('abc', 'b', 2);
     * // => true
     */
    function endsWith(string, target, position) {
      string = toString(string);
      target = baseToString(target);

      var length = string.length;
      position = position === undefined
        ? length
        : baseClamp(toInteger(position), 0, length);

      var end = position;
      position -= target.length;
      return position >= 0 && string.slice(position, end) == target;
    }

    /**
     * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
     * corresponding HTML entities.
     *
     * **Note:** No other characters are escaped. To escape additional
     * characters use a third-party library like [_he_](https://mths.be/he).
     *
     * Though the ">" character is escaped for symmetry, characters like
     * ">" and "/" don't need escaping in HTML and have no special meaning
     * unless they're part of a tag or unquoted attribute value. See
     * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
     * (under "semi-related fun fact") for more details.
     *
     * When working with HTML you should always
     * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
     * XSS vectors.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category String
     * @param {string} [string=''] The string to escape.
     * @returns {string} Returns the escaped string.
     * @example
     *
     * _.escape('fred, barney, & pebbles');
     * // => 'fred, barney, &amp; pebbles'
     */
    function escape(string) {
      string = toString(string);
      return (string && reHasUnescapedHtml.test(string))
        ? string.replace(reUnescapedHtml, escapeHtmlChar)
        : string;
    }

    /**
     * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
     * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to escape.
     * @returns {string} Returns the escaped string.
     * @example
     *
     * _.escapeRegExp('[lodash](https://lodash.com/)');
     * // => '\[lodash\]\(https://lodash\.com/\)'
     */
    function escapeRegExp(string) {
      string = toString(string);
      return (string && reHasRegExpChar.test(string))
        ? string.replace(reRegExpChar, '\\$&')
        : string;
    }

    /**
     * Converts `string` to
     * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the kebab cased string.
     * @example
     *
     * _.kebabCase('Foo Bar');
     * // => 'foo-bar'
     *
     * _.kebabCase('fooBar');
     * // => 'foo-bar'
     *
     * _.kebabCase('__FOO_BAR__');
     * // => 'foo-bar'
     */
    var kebabCase = createCompounder(function(result, word, index) {
      return result + (index ? '-' : '') + word.toLowerCase();
    });

    /**
     * Converts `string`, as space separated words, to lower case.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the lower cased string.
     * @example
     *
     * _.lowerCase('--Foo-Bar--');
     * // => 'foo bar'
     *
     * _.lowerCase('fooBar');
     * // => 'foo bar'
     *
     * _.lowerCase('__FOO_BAR__');
     * // => 'foo bar'
     */
    var lowerCase = createCompounder(function(result, word, index) {
      return result + (index ? ' ' : '') + word.toLowerCase();
    });

    /**
     * Converts the first character of `string` to lower case.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the converted string.
     * @example
     *
     * _.lowerFirst('Fred');
     * // => 'fred'
     *
     * _.lowerFirst('FRED');
     * // => 'fRED'
     */
    var lowerFirst = createCaseFirst('toLowerCase');

    /**
     * Pads `string` on the left and right sides if it's shorter than `length`.
     * Padding characters are truncated if they can't be evenly divided by `length`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to pad.
     * @param {number} [length=0] The padding length.
     * @param {string} [chars=' '] The string used as padding.
     * @returns {string} Returns the padded string.
     * @example
     *
     * _.pad('abc', 8);
     * // => '  abc   '
     *
     * _.pad('abc', 8, '_-');
     * // => '_-abc_-_'
     *
     * _.pad('abc', 3);
     * // => 'abc'
     */
    function pad(string, length, chars) {
      string = toString(string);
      length = toInteger(length);

      var strLength = length ? stringSize(string) : 0;
      if (!length || strLength >= length) {
        return string;
      }
      var mid = (length - strLength) / 2;
      return (
        createPadding(nativeFloor(mid), chars) +
        string +
        createPadding(nativeCeil(mid), chars)
      );
    }

    /**
     * Pads `string` on the right side if it's shorter than `length`. Padding
     * characters are truncated if they exceed `length`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to pad.
     * @param {number} [length=0] The padding length.
     * @param {string} [chars=' '] The string used as padding.
     * @returns {string} Returns the padded string.
     * @example
     *
     * _.padEnd('abc', 6);
     * // => 'abc   '
     *
     * _.padEnd('abc', 6, '_-');
     * // => 'abc_-_'
     *
     * _.padEnd('abc', 3);
     * // => 'abc'
     */
    function padEnd(string, length, chars) {
      string = toString(string);
      length = toInteger(length);

      var strLength = length ? stringSize(string) : 0;
      return (length && strLength < length)
        ? (string + createPadding(length - strLength, chars))
        : string;
    }

    /**
     * Pads `string` on the left side if it's shorter than `length`. Padding
     * characters are truncated if they exceed `length`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to pad.
     * @param {number} [length=0] The padding length.
     * @param {string} [chars=' '] The string used as padding.
     * @returns {string} Returns the padded string.
     * @example
     *
     * _.padStart('abc', 6);
     * // => '   abc'
     *
     * _.padStart('abc', 6, '_-');
     * // => '_-_abc'
     *
     * _.padStart('abc', 3);
     * // => 'abc'
     */
    function padStart(string, length, chars) {
      string = toString(string);
      length = toInteger(length);

      var strLength = length ? stringSize(string) : 0;
      return (length && strLength < length)
        ? (createPadding(length - strLength, chars) + string)
        : string;
    }

    /**
     * Converts `string` to an integer of the specified radix. If `radix` is
     * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
     * hexadecimal, in which case a `radix` of `16` is used.
     *
     * **Note:** This method aligns with the
     * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
     *
     * @static
     * @memberOf _
     * @since 1.1.0
     * @category String
     * @param {string} string The string to convert.
     * @param {number} [radix=10] The radix to interpret `value` by.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {number} Returns the converted integer.
     * @example
     *
     * _.parseInt('08');
     * // => 8
     *
     * _.map(['6', '08', '10'], _.parseInt);
     * // => [6, 8, 10]
     */
    function parseInt(string, radix, guard) {
      if (guard || radix == null) {
        radix = 0;
      } else if (radix) {
        radix = +radix;
      }
      return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
    }

    /**
     * Repeats the given string `n` times.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to repeat.
     * @param {number} [n=1] The number of times to repeat the string.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {string} Returns the repeated string.
     * @example
     *
     * _.repeat('*', 3);
     * // => '***'
     *
     * _.repeat('abc', 2);
     * // => 'abcabc'
     *
     * _.repeat('abc', 0);
     * // => ''
     */
    function repeat(string, n, guard) {
      if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
        n = 1;
      } else {
        n = toInteger(n);
      }
      return baseRepeat(toString(string), n);
    }

    /**
     * Replaces matches for `pattern` in `string` with `replacement`.
     *
     * **Note:** This method is based on
     * [`String#replace`](https://mdn.io/String/replace).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to modify.
     * @param {RegExp|string} pattern The pattern to replace.
     * @param {Function|string} replacement The match replacement.
     * @returns {string} Returns the modified string.
     * @example
     *
     * _.replace('Hi Fred', 'Fred', 'Barney');
     * // => 'Hi Barney'
     */
    function replace() {
      var args = arguments,
          string = toString(args[0]);

      return args.length < 3 ? string : string.replace(args[1], args[2]);
    }

    /**
     * Converts `string` to
     * [snake case](https://en.wikipedia.org/wiki/Snake_case).
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the snake cased string.
     * @example
     *
     * _.snakeCase('Foo Bar');
     * // => 'foo_bar'
     *
     * _.snakeCase('fooBar');
     * // => 'foo_bar'
     *
     * _.snakeCase('--FOO-BAR--');
     * // => 'foo_bar'
     */
    var snakeCase = createCompounder(function(result, word, index) {
      return result + (index ? '_' : '') + word.toLowerCase();
    });

    /**
     * Splits `string` by `separator`.
     *
     * **Note:** This method is based on
     * [`String#split`](https://mdn.io/String/split).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to split.
     * @param {RegExp|string} separator The separator pattern to split by.
     * @param {number} [limit] The length to truncate results to.
     * @returns {Array} Returns the string segments.
     * @example
     *
     * _.split('a-b-c', '-', 2);
     * // => ['a', 'b']
     */
    function split(string, separator, limit) {
      if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
        separator = limit = undefined;
      }
      limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
      if (!limit) {
        return [];
      }
      string = toString(string);
      if (string && (
            typeof separator == 'string' ||
            (separator != null && !isRegExp(separator))
          )) {
        separator = baseToString(separator);
        if (!separator && hasUnicode(string)) {
          return castSlice(stringToArray(string), 0, limit);
        }
      }
      return string.split(separator, limit);
    }

    /**
     * Converts `string` to
     * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
     *
     * @static
     * @memberOf _
     * @since 3.1.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the start cased string.
     * @example
     *
     * _.startCase('--foo-bar--');
     * // => 'Foo Bar'
     *
     * _.startCase('fooBar');
     * // => 'Foo Bar'
     *
     * _.startCase('__FOO_BAR__');
     * // => 'FOO BAR'
     */
    var startCase = createCompounder(function(result, word, index) {
      return result + (index ? ' ' : '') + upperFirst(word);
    });

    /**
     * Checks if `string` starts with the given target string.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to inspect.
     * @param {string} [target] The string to search for.
     * @param {number} [position=0] The position to search from.
     * @returns {boolean} Returns `true` if `string` starts with `target`,
     *  else `false`.
     * @example
     *
     * _.startsWith('abc', 'a');
     * // => true
     *
     * _.startsWith('abc', 'b');
     * // => false
     *
     * _.startsWith('abc', 'b', 1);
     * // => true
     */
    function startsWith(string, target, position) {
      string = toString(string);
      position = position == null
        ? 0
        : baseClamp(toInteger(position), 0, string.length);

      target = baseToString(target);
      return string.slice(position, position + target.length) == target;
    }

    /**
     * Creates a compiled template function that can interpolate data properties
     * in "interpolate" delimiters, HTML-escape interpolated data properties in
     * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
     * properties may be accessed as free variables in the template. If a setting
     * object is given, it takes precedence over `_.templateSettings` values.
     *
     * **Note:** In the development build `_.template` utilizes
     * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
     * for easier debugging.
     *
     * For more information on precompiling templates see
     * [lodash's custom builds documentation](https://lodash.com/custom-builds).
     *
     * For more information on Chrome extension sandboxes see
     * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category String
     * @param {string} [string=''] The template string.
     * @param {Object} [options={}] The options object.
     * @param {RegExp} [options.escape=_.templateSettings.escape]
     *  The HTML "escape" delimiter.
     * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
     *  The "evaluate" delimiter.
     * @param {Object} [options.imports=_.templateSettings.imports]
     *  An object to import into the template as free variables.
     * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
     *  The "interpolate" delimiter.
     * @param {string} [options.sourceURL='lodash.templateSources[n]']
     *  The sourceURL of the compiled template.
     * @param {string} [options.variable='obj']
     *  The data object variable name.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Function} Returns the compiled template function.
     * @example
     *
     * // Use the "interpolate" delimiter to create a compiled template.
     * var compiled = _.template('hello <%= user %>!');
     * compiled({ 'user': 'fred' });
     * // => 'hello fred!'
     *
     * // Use the HTML "escape" delimiter to escape data property values.
     * var compiled = _.template('<b><%- value %></b>');
     * compiled({ 'value': '<script>' });
     * // => '<b>&lt;script&gt;</b>'
     *
     * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
     * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
     * compiled({ 'users': ['fred', 'barney'] });
     * // => '<li>fred</li><li>barney</li>'
     *
     * // Use the internal `print` function in "evaluate" delimiters.
     * var compiled = _.template('<% print("hello " + user); %>!');
     * compiled({ 'user': 'barney' });
     * // => 'hello barney!'
     *
     * // Use the ES template literal delimiter as an "interpolate" delimiter.
     * // Disable support by replacing the "interpolate" delimiter.
     * var compiled = _.template('hello ${ user }!');
     * compiled({ 'user': 'pebbles' });
     * // => 'hello pebbles!'
     *
     * // Use backslashes to treat delimiters as plain text.
     * var compiled = _.template('<%= "\\<%- value %\\>" %>');
     * compiled({ 'value': 'ignored' });
     * // => '<%- value %>'
     *
     * // Use the `imports` option to import `jQuery` as `jq`.
     * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
     * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
     * compiled({ 'users': ['fred', 'barney'] });
     * // => '<li>fred</li><li>barney</li>'
     *
     * // Use the `sourceURL` option to specify a custom sourceURL for the template.
     * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
     * compiled(data);
     * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
     *
     * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
     * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
     * compiled.source;
     * // => function(data) {
     * //   var __t, __p = '';
     * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
     * //   return __p;
     * // }
     *
     * // Use custom template delimiters.
     * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
     * var compiled = _.template('hello {{ user }}!');
     * compiled({ 'user': 'mustache' });
     * // => 'hello mustache!'
     *
     * // Use the `source` property to inline compiled templates for meaningful
     * // line numbers in error messages and stack traces.
     * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
     *   var JST = {\
     *     "main": ' + _.template(mainText).source + '\
     *   };\
     * ');
     */
    function template(string, options, guard) {
      // Based on John Resig's `tmpl` implementation
      // (http://ejohn.org/blog/javascript-micro-templating/)
      // and Laura Doktorova's doT.js (https://github.com/olado/doT).
      var settings = lodash.templateSettings;

      if (guard && isIterateeCall(string, options, guard)) {
        options = undefined;
      }
      string = toString(string);
      options = assignInWith({}, options, settings, customDefaultsAssignIn);

      var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
          importsKeys = keys(imports),
          importsValues = baseValues(imports, importsKeys);

      var isEscaping,
          isEvaluating,
          index = 0,
          interpolate = options.interpolate || reNoMatch,
          source = "__p += '";

      // Compile the regexp to match each delimiter.
      var reDelimiters = RegExp(
        (options.escape || reNoMatch).source + '|' +
        interpolate.source + '|' +
        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
        (options.evaluate || reNoMatch).source + '|$'
      , 'g');

      // Use a sourceURL for easier debugging.
      // The sourceURL gets injected into the source that's eval-ed, so be careful
      // to normalize all kinds of whitespace, so e.g. newlines (and unicode versions of it) can't sneak in
      // and escape the comment, thus injecting code that gets evaled.
      var sourceURL = '//# sourceURL=' +
        (hasOwnProperty.call(options, 'sourceURL')
          ? (options.sourceURL + '').replace(/\s/g, ' ')
          : ('lodash.templateSources[' + (++templateCounter) + ']')
        ) + '\n';

      string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
        interpolateValue || (interpolateValue = esTemplateValue);

        // Escape characters that can't be included in string literals.
        source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);

        // Replace delimiters with snippets.
        if (escapeValue) {
          isEscaping = true;
          source += "' +\n__e(" + escapeValue + ") +\n'";
        }
        if (evaluateValue) {
          isEvaluating = true;
          source += "';\n" + evaluateValue + ";\n__p += '";
        }
        if (interpolateValue) {
          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
        }
        index = offset + match.length;

        // The JS engine embedded in Adobe products needs `match` returned in
        // order to produce the correct `offset` value.
        return match;
      });

      source += "';\n";

      // If `variable` is not specified wrap a with-statement around the generated
      // code to add the data object to the top of the scope chain.
      var variable = hasOwnProperty.call(options, 'variable') && options.variable;
      if (!variable) {
        source = 'with (obj) {\n' + source + '\n}\n';
      }
      // Throw an error if a forbidden character was found in `variable`, to prevent
      // potential command injection attacks.
      else if (reForbiddenIdentifierChars.test(variable)) {
        throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT);
      }

      // Cleanup code by stripping empty strings.
      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
        .replace(reEmptyStringMiddle, '$1')
        .replace(reEmptyStringTrailing, '$1;');

      // Frame code as the function body.
      source = 'function(' + (variable || 'obj') + ') {\n' +
        (variable
          ? ''
          : 'obj || (obj = {});\n'
        ) +
        "var __t, __p = ''" +
        (isEscaping
           ? ', __e = _.escape'
           : ''
        ) +
        (isEvaluating
          ? ', __j = Array.prototype.join;\n' +
            "function print() { __p += __j.call(arguments, '') }\n"
          : ';\n'
        ) +
        source +
        'return __p\n}';

      var result = attempt(function() {
        return Function(importsKeys, sourceURL + 'return ' + source)
          .apply(undefined, importsValues);
      });

      // Provide the compiled function's source by its `toString` method or
      // the `source` property as a convenience for inlining compiled templates.
      result.source = source;
      if (isError(result)) {
        throw result;
      }
      return result;
    }

    /**
     * Converts `string`, as a whole, to lower case just like
     * [String#toLowerCase](https://mdn.io/toLowerCase).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the lower cased string.
     * @example
     *
     * _.toLower('--Foo-Bar--');
     * // => '--foo-bar--'
     *
     * _.toLower('fooBar');
     * // => 'foobar'
     *
     * _.toLower('__FOO_BAR__');
     * // => '__foo_bar__'
     */
    function toLower(value) {
      return toString(value).toLowerCase();
    }

    /**
     * Converts `string`, as a whole, to upper case just like
     * [String#toUpperCase](https://mdn.io/toUpperCase).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the upper cased string.
     * @example
     *
     * _.toUpper('--foo-bar--');
     * // => '--FOO-BAR--'
     *
     * _.toUpper('fooBar');
     * // => 'FOOBAR'
     *
     * _.toUpper('__foo_bar__');
     * // => '__FOO_BAR__'
     */
    function toUpper(value) {
      return toString(value).toUpperCase();
    }

    /**
     * Removes leading and trailing whitespace or specified characters from `string`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to trim.
     * @param {string} [chars=whitespace] The characters to trim.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {string} Returns the trimmed string.
     * @example
     *
     * _.trim('  abc  ');
     * // => 'abc'
     *
     * _.trim('-_-abc-_-', '_-');
     * // => 'abc'
     *
     * _.map(['  foo  ', '  bar  '], _.trim);
     * // => ['foo', 'bar']
     */
    function trim(string, chars, guard) {
      string = toString(string);
      if (string && (guard || chars === undefined)) {
        return baseTrim(string);
      }
      if (!string || !(chars = baseToString(chars))) {
        return string;
      }
      var strSymbols = stringToArray(string),
          chrSymbols = stringToArray(chars),
          start = charsStartIndex(strSymbols, chrSymbols),
          end = charsEndIndex(strSymbols, chrSymbols) + 1;

      return castSlice(strSymbols, start, end).join('');
    }

    /**
     * Removes trailing whitespace or specified characters from `string`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to trim.
     * @param {string} [chars=whitespace] The characters to trim.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {string} Returns the trimmed string.
     * @example
     *
     * _.trimEnd('  abc  ');
     * // => '  abc'
     *
     * _.trimEnd('-_-abc-_-', '_-');
     * // => '-_-abc'
     */
    function trimEnd(string, chars, guard) {
      string = toString(string);
      if (string && (guard || chars === undefined)) {
        return string.slice(0, trimmedEndIndex(string) + 1);
      }
      if (!string || !(chars = baseToString(chars))) {
        return string;
      }
      var strSymbols = stringToArray(string),
          end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;

      return castSlice(strSymbols, 0, end).join('');
    }

    /**
     * Removes leading whitespace or specified characters from `string`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to trim.
     * @param {string} [chars=whitespace] The characters to trim.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {string} Returns the trimmed string.
     * @example
     *
     * _.trimStart('  abc  ');
     * // => 'abc  '
     *
     * _.trimStart('-_-abc-_-', '_-');
     * // => 'abc-_-'
     */
    function trimStart(string, chars, guard) {
      string = toString(string);
      if (string && (guard || chars === undefined)) {
        return string.replace(reTrimStart, '');
      }
      if (!string || !(chars = baseToString(chars))) {
        return string;
      }
      var strSymbols = stringToArray(string),
          start = charsStartIndex(strSymbols, stringToArray(chars));

      return castSlice(strSymbols, start).join('');
    }

    /**
     * Truncates `string` if it's longer than the given maximum string length.
     * The last characters of the truncated string are replaced with the omission
     * string which defaults to "...".
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to truncate.
     * @param {Object} [options={}] The options object.
     * @param {number} [options.length=30] The maximum string length.
     * @param {string} [options.omission='...'] The string to indicate text is omitted.
     * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
     * @returns {string} Returns the truncated string.
     * @example
     *
     * _.truncate('hi-diddly-ho there, neighborino');
     * // => 'hi-diddly-ho there, neighbo...'
     *
     * _.truncate('hi-diddly-ho there, neighborino', {
     *   'length': 24,
     *   'separator': ' '
     * });
     * // => 'hi-diddly-ho there,...'
     *
     * _.truncate('hi-diddly-ho there, neighborino', {
     *   'length': 24,
     *   'separator': /,? +/
     * });
     * // => 'hi-diddly-ho there...'
     *
     * _.truncate('hi-diddly-ho there, neighborino', {
     *   'omission': ' [...]'
     * });
     * // => 'hi-diddly-ho there, neig [...]'
     */
    function truncate(string, options) {
      var length = DEFAULT_TRUNC_LENGTH,
          omission = DEFAULT_TRUNC_OMISSION;

      if (isObject(options)) {
        var separator = 'separator' in options ? options.separator : separator;
        length = 'length' in options ? toInteger(options.length) : length;
        omission = 'omission' in options ? baseToString(options.omission) : omission;
      }
      string = toString(string);

      var strLength = string.length;
      if (hasUnicode(string)) {
        var strSymbols = stringToArray(string);
        strLength = strSymbols.length;
      }
      if (length >= strLength) {
        return string;
      }
      var end = length - stringSize(omission);
      if (end < 1) {
        return omission;
      }
      var result = strSymbols
        ? castSlice(strSymbols, 0, end).join('')
        : string.slice(0, end);

      if (separator === undefined) {
        return result + omission;
      }
      if (strSymbols) {
        end += (result.length - end);
      }
      if (isRegExp(separator)) {
        if (string.slice(end).search(separator)) {
          var match,
              substring = result;

          if (!separator.global) {
            separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
          }
          separator.lastIndex = 0;
          while ((match = separator.exec(substring))) {
            var newEnd = match.index;
          }
          result = result.slice(0, newEnd === undefined ? end : newEnd);
        }
      } else if (string.indexOf(baseToString(separator), end) != end) {
        var index = result.lastIndexOf(separator);
        if (index > -1) {
          result = result.slice(0, index);
        }
      }
      return result + omission;
    }

    /**
     * The inverse of `_.escape`; this method converts the HTML entities
     * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
     * their corresponding characters.
     *
     * **Note:** No other HTML entities are unescaped. To unescape additional
     * HTML entities use a third-party library like [_he_](https://mths.be/he).
     *
     * @static
     * @memberOf _
     * @since 0.6.0
     * @category String
     * @param {string} [string=''] The string to unescape.
     * @returns {string} Returns the unescaped string.
     * @example
     *
     * _.unescape('fred, barney, &amp; pebbles');
     * // => 'fred, barney, & pebbles'
     */
    function unescape(string) {
      string = toString(string);
      return (string && reHasEscapedHtml.test(string))
        ? string.replace(reEscapedHtml, unescapeHtmlChar)
        : string;
    }

    /**
     * Converts `string`, as space separated words, to upper case.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the upper cased string.
     * @example
     *
     * _.upperCase('--foo-bar');
     * // => 'FOO BAR'
     *
     * _.upperCase('fooBar');
     * // => 'FOO BAR'
     *
     * _.upperCase('__foo_bar__');
     * // => 'FOO BAR'
     */
    var upperCase = createCompounder(function(result, word, index) {
      return result + (index ? ' ' : '') + word.toUpperCase();
    });

    /**
     * Converts the first character of `string` to upper case.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category String
     * @param {string} [string=''] The string to convert.
     * @returns {string} Returns the converted string.
     * @example
     *
     * _.upperFirst('fred');
     * // => 'Fred'
     *
     * _.upperFirst('FRED');
     * // => 'FRED'
     */
    var upperFirst = createCaseFirst('toUpperCase');

    /**
     * Splits `string` into an array of its words.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category String
     * @param {string} [string=''] The string to inspect.
     * @param {RegExp|string} [pattern] The pattern to match words.
     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
     * @returns {Array} Returns the words of `string`.
     * @example
     *
     * _.words('fred, barney, & pebbles');
     * // => ['fred', 'barney', 'pebbles']
     *
     * _.words('fred, barney, & pebbles', /[^, ]+/g);
     * // => ['fred', 'barney', '&', 'pebbles']
     */
    function words(string, pattern, guard) {
      string = toString(string);
      pattern = guard ? undefined : pattern;

      if (pattern === undefined) {
        return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
      }
      return string.match(pattern) || [];
    }

    /*------------------------------------------------------------------------*/

    /**
     * Attempts to invoke `func`, returning either the result or the caught error
     * object. Any additional arguments are provided to `func` when it's invoked.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Util
     * @param {Function} func The function to attempt.
     * @param {...*} [args] The arguments to invoke `func` with.
     * @returns {*} Returns the `func` result or error object.
     * @example
     *
     * // Avoid throwing errors for invalid selectors.
     * var elements = _.attempt(function(selector) {
     *   return document.querySelectorAll(selector);
     * }, '>_>');
     *
     * if (_.isError(elements)) {
     *   elements = [];
     * }
     */
    var attempt = baseRest(function(func, args) {
      try {
        return apply(func, undefined, args);
      } catch (e) {
        return isError(e) ? e : new Error(e);
      }
    });

    /**
     * Binds methods of an object to the object itself, overwriting the existing
     * method.
     *
     * **Note:** This method doesn't set the "length" property of bound functions.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {Object} object The object to bind and assign the bound methods to.
     * @param {...(string|string[])} methodNames The object method names to bind.
     * @returns {Object} Returns `object`.
     * @example
     *
     * var view = {
     *   'label': 'docs',
     *   'click': function() {
     *     console.log('clicked ' + this.label);
     *   }
     * };
     *
     * _.bindAll(view, ['click']);
     * jQuery(element).on('click', view.click);
     * // => Logs 'clicked docs' when clicked.
     */
    var bindAll = flatRest(function(object, methodNames) {
      arrayEach(methodNames, function(key) {
        key = toKey(key);
        baseAssignValue(object, key, bind(object[key], object));
      });
      return object;
    });

    /**
     * Creates a function that iterates over `pairs` and invokes the corresponding
     * function of the first predicate to return truthy. The predicate-function
     * pairs are invoked with the `this` binding and arguments of the created
     * function.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {Array} pairs The predicate-function pairs.
     * @returns {Function} Returns the new composite function.
     * @example
     *
     * var func = _.cond([
     *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
     *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
     *   [_.stubTrue,                      _.constant('no match')]
     * ]);
     *
     * func({ 'a': 1, 'b': 2 });
     * // => 'matches A'
     *
     * func({ 'a': 0, 'b': 1 });
     * // => 'matches B'
     *
     * func({ 'a': '1', 'b': '2' });
     * // => 'no match'
     */
    function cond(pairs) {
      var length = pairs == null ? 0 : pairs.length,
          toIteratee = getIteratee();

      pairs = !length ? [] : arrayMap(pairs, function(pair) {
        if (typeof pair[1] != 'function') {
          throw new TypeError(FUNC_ERROR_TEXT);
        }
        return [toIteratee(pair[0]), pair[1]];
      });

      return baseRest(function(args) {
        var index = -1;
        while (++index < length) {
          var pair = pairs[index];
          if (apply(pair[0], this, args)) {
            return apply(pair[1], this, args);
          }
        }
      });
    }

    /**
     * Creates a function that invokes the predicate properties of `source` with
     * the corresponding property values of a given object, returning `true` if
     * all predicates return truthy, else `false`.
     *
     * **Note:** The created function is equivalent to `_.conformsTo` with
     * `source` partially applied.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {Object} source The object of property predicates to conform to.
     * @returns {Function} Returns the new spec function.
     * @example
     *
     * var objects = [
     *   { 'a': 2, 'b': 1 },
     *   { 'a': 1, 'b': 2 }
     * ];
     *
     * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
     * // => [{ 'a': 1, 'b': 2 }]
     */
    function conforms(source) {
      return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
    }

    /**
     * Creates a function that returns `value`.
     *
     * @static
     * @memberOf _
     * @since 2.4.0
     * @category Util
     * @param {*} value The value to return from the new function.
     * @returns {Function} Returns the new constant function.
     * @example
     *
     * var objects = _.times(2, _.constant({ 'a': 1 }));
     *
     * console.log(objects);
     * // => [{ 'a': 1 }, { 'a': 1 }]
     *
     * console.log(objects[0] === objects[1]);
     * // => true
     */
    function constant(value) {
      return function() {
        return value;
      };
    }

    /**
     * Checks `value` to determine whether a default value should be returned in
     * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
     * or `undefined`.
     *
     * @static
     * @memberOf _
     * @since 4.14.0
     * @category Util
     * @param {*} value The value to check.
     * @param {*} defaultValue The default value.
     * @returns {*} Returns the resolved value.
     * @example
     *
     * _.defaultTo(1, 10);
     * // => 1
     *
     * _.defaultTo(undefined, 10);
     * // => 10
     */
    function defaultTo(value, defaultValue) {
      return (value == null || value !== value) ? defaultValue : value;
    }

    /**
     * Creates a function that returns the result of invoking the given functions
     * with the `this` binding of the created function, where each successive
     * invocation is supplied the return value of the previous.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Util
     * @param {...(Function|Function[])} [funcs] The functions to invoke.
     * @returns {Function} Returns the new composite function.
     * @see _.flowRight
     * @example
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * var addSquare = _.flow([_.add, square]);
     * addSquare(1, 2);
     * // => 9
     */
    var flow = createFlow();

    /**
     * This method is like `_.flow` except that it creates a function that
     * invokes the given functions from right to left.
     *
     * @static
     * @since 3.0.0
     * @memberOf _
     * @category Util
     * @param {...(Function|Function[])} [funcs] The functions to invoke.
     * @returns {Function} Returns the new composite function.
     * @see _.flow
     * @example
     *
     * function square(n) {
     *   return n * n;
     * }
     *
     * var addSquare = _.flowRight([square, _.add]);
     * addSquare(1, 2);
     * // => 9
     */
    var flowRight = createFlow(true);

    /**
     * This method returns the first argument it receives.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {*} value Any value.
     * @returns {*} Returns `value`.
     * @example
     *
     * var object = { 'a': 1 };
     *
     * console.log(_.identity(object) === object);
     * // => true
     */
    function identity(value) {
      return value;
    }

    /**
     * Creates a function that invokes `func` with the arguments of the created
     * function. If `func` is a property name, the created function returns the
     * property value for a given element. If `func` is an array or object, the
     * created function returns `true` for elements that contain the equivalent
     * source properties, otherwise it returns `false`.
     *
     * @static
     * @since 4.0.0
     * @memberOf _
     * @category Util
     * @param {*} [func=_.identity] The value to convert to a callback.
     * @returns {Function} Returns the callback.
     * @example
     *
     * var users = [
     *   { 'user': 'barney', 'age': 36, 'active': true },
     *   { 'user': 'fred',   'age': 40, 'active': false }
     * ];
     *
     * // The `_.matches` iteratee shorthand.
     * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
     * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
     *
     * // The `_.matchesProperty` iteratee shorthand.
     * _.filter(users, _.iteratee(['user', 'fred']));
     * // => [{ 'user': 'fred', 'age': 40 }]
     *
     * // The `_.property` iteratee shorthand.
     * _.map(users, _.iteratee('user'));
     * // => ['barney', 'fred']
     *
     * // Create custom iteratee shorthands.
     * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
     *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
     *     return func.test(string);
     *   };
     * });
     *
     * _.filter(['abc', 'def'], /ef/);
     * // => ['def']
     */
    function iteratee(func) {
      return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
    }

    /**
     * Creates a function that performs a partial deep comparison between a given
     * object and `source`, returning `true` if the given object has equivalent
     * property values, else `false`.
     *
     * **Note:** The created function is equivalent to `_.isMatch` with `source`
     * partially applied.
     *
     * Partial comparisons will match empty array and empty object `source`
     * values against any array or object value, respectively. See `_.isEqual`
     * for a list of supported value comparisons.
     *
     * **Note:** Multiple values can be checked by combining several matchers
     * using `_.overSome`
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Util
     * @param {Object} source The object of property values to match.
     * @returns {Function} Returns the new spec function.
     * @example
     *
     * var objects = [
     *   { 'a': 1, 'b': 2, 'c': 3 },
     *   { 'a': 4, 'b': 5, 'c': 6 }
     * ];
     *
     * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
     * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
     *
     * // Checking for several possible values
     * _.filter(objects, _.overSome([_.matches({ 'a': 1 }), _.matches({ 'a': 4 })]));
     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
     */
    function matches(source) {
      return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
    }

    /**
     * Creates a function that performs a partial deep comparison between the
     * value at `path` of a given object to `srcValue`, returning `true` if the
     * object value is equivalent, else `false`.
     *
     * **Note:** Partial comparisons will match empty array and empty object
     * `srcValue` values against any array or object value, respectively. See
     * `_.isEqual` for a list of supported value comparisons.
     *
     * **Note:** Multiple values can be checked by combining several matchers
     * using `_.overSome`
     *
     * @static
     * @memberOf _
     * @since 3.2.0
     * @category Util
     * @param {Array|string} path The path of the property to get.
     * @param {*} srcValue The value to match.
     * @returns {Function} Returns the new spec function.
     * @example
     *
     * var objects = [
     *   { 'a': 1, 'b': 2, 'c': 3 },
     *   { 'a': 4, 'b': 5, 'c': 6 }
     * ];
     *
     * _.find(objects, _.matchesProperty('a', 4));
     * // => { 'a': 4, 'b': 5, 'c': 6 }
     *
     * // Checking for several possible values
     * _.filter(objects, _.overSome([_.matchesProperty('a', 1), _.matchesProperty('a', 4)]));
     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
     */
    function matchesProperty(path, srcValue) {
      return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
    }

    /**
     * Creates a function that invokes the method at `path` of a given object.
     * Any additional arguments are provided to the invoked method.
     *
     * @static
     * @memberOf _
     * @since 3.7.0
     * @category Util
     * @param {Array|string} path The path of the method to invoke.
     * @param {...*} [args] The arguments to invoke the method with.
     * @returns {Function} Returns the new invoker function.
     * @example
     *
     * var objects = [
     *   { 'a': { 'b': _.constant(2) } },
     *   { 'a': { 'b': _.constant(1) } }
     * ];
     *
     * _.map(objects, _.method('a.b'));
     * // => [2, 1]
     *
     * _.map(objects, _.method(['a', 'b']));
     * // => [2, 1]
     */
    var method = baseRest(function(path, args) {
      return function(object) {
        return baseInvoke(object, path, args);
      };
    });

    /**
     * The opposite of `_.method`; this method creates a function that invokes
     * the method at a given path of `object`. Any additional arguments are
     * provided to the invoked method.
     *
     * @static
     * @memberOf _
     * @since 3.7.0
     * @category Util
     * @param {Object} object The object to query.
     * @param {...*} [args] The arguments to invoke the method with.
     * @returns {Function} Returns the new invoker function.
     * @example
     *
     * var array = _.times(3, _.constant),
     *     object = { 'a': array, 'b': array, 'c': array };
     *
     * _.map(['a[2]', 'c[0]'], _.methodOf(object));
     * // => [2, 0]
     *
     * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
     * // => [2, 0]
     */
    var methodOf = baseRest(function(object, args) {
      return function(path) {
        return baseInvoke(object, path, args);
      };
    });

    /**
     * Adds all own enumerable string keyed function properties of a source
     * object to the destination object. If `object` is a function, then methods
     * are added to its prototype as well.
     *
     * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
     * avoid conflicts caused by modifying the original.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {Function|Object} [object=lodash] The destination object.
     * @param {Object} source The object of functions to add.
     * @param {Object} [options={}] The options object.
     * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
     * @returns {Function|Object} Returns `object`.
     * @example
     *
     * function vowels(string) {
     *   return _.filter(string, function(v) {
     *     return /[aeiou]/i.test(v);
     *   });
     * }
     *
     * _.mixin({ 'vowels': vowels });
     * _.vowels('fred');
     * // => ['e']
     *
     * _('fred').vowels().value();
     * // => ['e']
     *
     * _.mixin({ 'vowels': vowels }, { 'chain': false });
     * _('fred').vowels();
     * // => ['e']
     */
    function mixin(object, source, options) {
      var props = keys(source),
          methodNames = baseFunctions(source, props);

      if (options == null &&
          !(isObject(source) && (methodNames.length || !props.length))) {
        options = source;
        source = object;
        object = this;
        methodNames = baseFunctions(source, keys(source));
      }
      var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
          isFunc = isFunction(object);

      arrayEach(methodNames, function(methodName) {
        var func = source[methodName];
        object[methodName] = func;
        if (isFunc) {
          object.prototype[methodName] = function() {
            var chainAll = this.__chain__;
            if (chain || chainAll) {
              var result = object(this.__wrapped__),
                  actions = result.__actions__ = copyArray(this.__actions__);

              actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
              result.__chain__ = chainAll;
              return result;
            }
            return func.apply(object, arrayPush([this.value()], arguments));
          };
        }
      });

      return object;
    }

    /**
     * Reverts the `_` variable to its previous value and returns a reference to
     * the `lodash` function.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @returns {Function} Returns the `lodash` function.
     * @example
     *
     * var lodash = _.noConflict();
     */
    function noConflict() {
      if (root._ === this) {
        root._ = oldDash;
      }
      return this;
    }

    /**
     * This method returns `undefined`.
     *
     * @static
     * @memberOf _
     * @since 2.3.0
     * @category Util
     * @example
     *
     * _.times(2, _.noop);
     * // => [undefined, undefined]
     */
    function noop() {
      // No operation performed.
    }

    /**
     * Creates a function that gets the argument at index `n`. If `n` is negative,
     * the nth argument from the end is returned.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {number} [n=0] The index of the argument to return.
     * @returns {Function} Returns the new pass-thru function.
     * @example
     *
     * var func = _.nthArg(1);
     * func('a', 'b', 'c', 'd');
     * // => 'b'
     *
     * var func = _.nthArg(-2);
     * func('a', 'b', 'c', 'd');
     * // => 'c'
     */
    function nthArg(n) {
      n = toInteger(n);
      return baseRest(function(args) {
        return baseNth(args, n);
      });
    }

    /**
     * Creates a function that invokes `iteratees` with the arguments it receives
     * and returns their results.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {...(Function|Function[])} [iteratees=[_.identity]]
     *  The iteratees to invoke.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var func = _.over([Math.max, Math.min]);
     *
     * func(1, 2, 3, 4);
     * // => [4, 1]
     */
    var over = createOver(arrayMap);

    /**
     * Creates a function that checks if **all** of the `predicates` return
     * truthy when invoked with the arguments it receives.
     *
     * Following shorthands are possible for providing predicates.
     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {...(Function|Function[])} [predicates=[_.identity]]
     *  The predicates to check.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var func = _.overEvery([Boolean, isFinite]);
     *
     * func('1');
     * // => true
     *
     * func(null);
     * // => false
     *
     * func(NaN);
     * // => false
     */
    var overEvery = createOver(arrayEvery);

    /**
     * Creates a function that checks if **any** of the `predicates` return
     * truthy when invoked with the arguments it receives.
     *
     * Following shorthands are possible for providing predicates.
     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {...(Function|Function[])} [predicates=[_.identity]]
     *  The predicates to check.
     * @returns {Function} Returns the new function.
     * @example
     *
     * var func = _.overSome([Boolean, isFinite]);
     *
     * func('1');
     * // => true
     *
     * func(null);
     * // => true
     *
     * func(NaN);
     * // => false
     *
     * var matchesFunc = _.overSome([{ 'a': 1 }, { 'a': 2 }])
     * var matchesPropertyFunc = _.overSome([['a', 1], ['a', 2]])
     */
    var overSome = createOver(arraySome);

    /**
     * Creates a function that returns the value at `path` of a given object.
     *
     * @static
     * @memberOf _
     * @since 2.4.0
     * @category Util
     * @param {Array|string} path The path of the property to get.
     * @returns {Function} Returns the new accessor function.
     * @example
     *
     * var objects = [
     *   { 'a': { 'b': 2 } },
     *   { 'a': { 'b': 1 } }
     * ];
     *
     * _.map(objects, _.property('a.b'));
     * // => [2, 1]
     *
     * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
     * // => [1, 2]
     */
    function property(path) {
      return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
    }

    /**
     * The opposite of `_.property`; this method creates a function that returns
     * the value at a given path of `object`.
     *
     * @static
     * @memberOf _
     * @since 3.0.0
     * @category Util
     * @param {Object} object The object to query.
     * @returns {Function} Returns the new accessor function.
     * @example
     *
     * var array = [0, 1, 2],
     *     object = { 'a': array, 'b': array, 'c': array };
     *
     * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
     * // => [2, 0]
     *
     * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
     * // => [2, 0]
     */
    function propertyOf(object) {
      return function(path) {
        return object == null ? undefined : baseGet(object, path);
      };
    }

    /**
     * Creates an array of numbers (positive and/or negative) progressing from
     * `start` up to, but not including, `end`. A step of `-1` is used if a negative
     * `start` is specified without an `end` or `step`. If `end` is not specified,
     * it's set to `start` with `start` then set to `0`.
     *
     * **Note:** JavaScript follows the IEEE-754 standard for resolving
     * floating-point values which can produce unexpected results.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {number} [start=0] The start of the range.
     * @param {number} end The end of the range.
     * @param {number} [step=1] The value to increment or decrement by.
     * @returns {Array} Returns the range of numbers.
     * @see _.inRange, _.rangeRight
     * @example
     *
     * _.range(4);
     * // => [0, 1, 2, 3]
     *
     * _.range(-4);
     * // => [0, -1, -2, -3]
     *
     * _.range(1, 5);
     * // => [1, 2, 3, 4]
     *
     * _.range(0, 20, 5);
     * // => [0, 5, 10, 15]
     *
     * _.range(0, -4, -1);
     * // => [0, -1, -2, -3]
     *
     * _.range(1, 4, 0);
     * // => [1, 1, 1]
     *
     * _.range(0);
     * // => []
     */
    var range = createRange();

    /**
     * This method is like `_.range` except that it populates values in
     * descending order.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {number} [start=0] The start of the range.
     * @param {number} end The end of the range.
     * @param {number} [step=1] The value to increment or decrement by.
     * @returns {Array} Returns the range of numbers.
     * @see _.inRange, _.range
     * @example
     *
     * _.rangeRight(4);
     * // => [3, 2, 1, 0]
     *
     * _.rangeRight(-4);
     * // => [-3, -2, -1, 0]
     *
     * _.rangeRight(1, 5);
     * // => [4, 3, 2, 1]
     *
     * _.rangeRight(0, 20, 5);
     * // => [15, 10, 5, 0]
     *
     * _.rangeRight(0, -4, -1);
     * // => [-3, -2, -1, 0]
     *
     * _.rangeRight(1, 4, 0);
     * // => [1, 1, 1]
     *
     * _.rangeRight(0);
     * // => []
     */
    var rangeRight = createRange(true);

    /**
     * This method returns a new empty array.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {Array} Returns the new empty array.
     * @example
     *
     * var arrays = _.times(2, _.stubArray);
     *
     * console.log(arrays);
     * // => [[], []]
     *
     * console.log(arrays[0] === arrays[1]);
     * // => false
     */
    function stubArray() {
      return [];
    }

    /**
     * This method returns `false`.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {boolean} Returns `false`.
     * @example
     *
     * _.times(2, _.stubFalse);
     * // => [false, false]
     */
    function stubFalse() {
      return false;
    }

    /**
     * This method returns a new empty object.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {Object} Returns the new empty object.
     * @example
     *
     * var objects = _.times(2, _.stubObject);
     *
     * console.log(objects);
     * // => [{}, {}]
     *
     * console.log(objects[0] === objects[1]);
     * // => false
     */
    function stubObject() {
      return {};
    }

    /**
     * This method returns an empty string.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {string} Returns the empty string.
     * @example
     *
     * _.times(2, _.stubString);
     * // => ['', '']
     */
    function stubString() {
      return '';
    }

    /**
     * This method returns `true`.
     *
     * @static
     * @memberOf _
     * @since 4.13.0
     * @category Util
     * @returns {boolean} Returns `true`.
     * @example
     *
     * _.times(2, _.stubTrue);
     * // => [true, true]
     */
    function stubTrue() {
      return true;
    }

    /**
     * Invokes the iteratee `n` times, returning an array of the results of
     * each invocation. The iteratee is invoked with one argument; (index).
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {number} n The number of times to invoke `iteratee`.
     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
     * @returns {Array} Returns the array of results.
     * @example
     *
     * _.times(3, String);
     * // => ['0', '1', '2']
     *
     *  _.times(4, _.constant(0));
     * // => [0, 0, 0, 0]
     */
    function times(n, iteratee) {
      n = toInteger(n);
      if (n < 1 || n > MAX_SAFE_INTEGER) {
        return [];
      }
      var index = MAX_ARRAY_LENGTH,
          length = nativeMin(n, MAX_ARRAY_LENGTH);

      iteratee = getIteratee(iteratee);
      n -= MAX_ARRAY_LENGTH;

      var result = baseTimes(length, iteratee);
      while (++index < n) {
        iteratee(index);
      }
      return result;
    }

    /**
     * Converts `value` to a property path array.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Util
     * @param {*} value The value to convert.
     * @returns {Array} Returns the new property path array.
     * @example
     *
     * _.toPath('a.b.c');
     * // => ['a', 'b', 'c']
     *
     * _.toPath('a[0].b.c');
     * // => ['a', '0', 'b', 'c']
     */
    function toPath(value) {
      if (isArray(value)) {
        return arrayMap(value, toKey);
      }
      return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
    }

    /**
     * Generates a unique ID. If `prefix` is given, the ID is appended to it.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Util
     * @param {string} [prefix=''] The value to prefix the ID with.
     * @returns {string} Returns the unique ID.
     * @example
     *
     * _.uniqueId('contact_');
     * // => 'contact_104'
     *
     * _.uniqueId();
     * // => '105'
     */
    function uniqueId(prefix) {
      var id = ++idCounter;
      return toString(prefix) + id;
    }

    /*------------------------------------------------------------------------*/

    /**
     * Adds two numbers.
     *
     * @static
     * @memberOf _
     * @since 3.4.0
     * @category Math
     * @param {number} augend The first number in an addition.
     * @param {number} addend The second number in an addition.
     * @returns {number} Returns the total.
     * @example
     *
     * _.add(6, 4);
     * // => 10
     */
    var add = createMathOperation(function(augend, addend) {
      return augend + addend;
    }, 0);

    /**
     * Computes `number` rounded up to `precision`.
     *
     * @static
     * @memberOf _
     * @since 3.10.0
     * @category Math
     * @param {number} number The number to round up.
     * @param {number} [precision=0] The precision to round up to.
     * @returns {number} Returns the rounded up number.
     * @example
     *
     * _.ceil(4.006);
     * // => 5
     *
     * _.ceil(6.004, 2);
     * // => 6.01
     *
     * _.ceil(6040, -2);
     * // => 6100
     */
    var ceil = createRound('ceil');

    /**
     * Divide two numbers.
     *
     * @static
     * @memberOf _
     * @since 4.7.0
     * @category Math
     * @param {number} dividend The first number in a division.
     * @param {number} divisor The second number in a division.
     * @returns {number} Returns the quotient.
     * @example
     *
     * _.divide(6, 4);
     * // => 1.5
     */
    var divide = createMathOperation(function(dividend, divisor) {
      return dividend / divisor;
    }, 1);

    /**
     * Computes `number` rounded down to `precision`.
     *
     * @static
     * @memberOf _
     * @since 3.10.0
     * @category Math
     * @param {number} number The number to round down.
     * @param {number} [precision=0] The precision to round down to.
     * @returns {number} Returns the rounded down number.
     * @example
     *
     * _.floor(4.006);
     * // => 4
     *
     * _.floor(0.046, 2);
     * // => 0.04
     *
     * _.floor(4060, -2);
     * // => 4000
     */
    var floor = createRound('floor');

    /**
     * Computes the maximum value of `array`. If `array` is empty or falsey,
     * `undefined` is returned.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Math
     * @param {Array} array The array to iterate over.
     * @returns {*} Returns the maximum value.
     * @example
     *
     * _.max([4, 2, 8, 6]);
     * // => 8
     *
     * _.max([]);
     * // => undefined
     */
    function max(array) {
      return (array && array.length)
        ? baseExtremum(array, identity, baseGt)
        : undefined;
    }

    /**
     * This method is like `_.max` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the criterion by which
     * the value is ranked. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {*} Returns the maximum value.
     * @example
     *
     * var objects = [{ 'n': 1 }, { 'n': 2 }];
     *
     * _.maxBy(objects, function(o) { return o.n; });
     * // => { 'n': 2 }
     *
     * // The `_.property` iteratee shorthand.
     * _.maxBy(objects, 'n');
     * // => { 'n': 2 }
     */
    function maxBy(array, iteratee) {
      return (array && array.length)
        ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
        : undefined;
    }

    /**
     * Computes the mean of the values in `array`.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @returns {number} Returns the mean.
     * @example
     *
     * _.mean([4, 2, 8, 6]);
     * // => 5
     */
    function mean(array) {
      return baseMean(array, identity);
    }

    /**
     * This method is like `_.mean` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the value to be averaged.
     * The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.7.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {number} Returns the mean.
     * @example
     *
     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
     *
     * _.meanBy(objects, function(o) { return o.n; });
     * // => 5
     *
     * // The `_.property` iteratee shorthand.
     * _.meanBy(objects, 'n');
     * // => 5
     */
    function meanBy(array, iteratee) {
      return baseMean(array, getIteratee(iteratee, 2));
    }

    /**
     * Computes the minimum value of `array`. If `array` is empty or falsey,
     * `undefined` is returned.
     *
     * @static
     * @since 0.1.0
     * @memberOf _
     * @category Math
     * @param {Array} array The array to iterate over.
     * @returns {*} Returns the minimum value.
     * @example
     *
     * _.min([4, 2, 8, 6]);
     * // => 2
     *
     * _.min([]);
     * // => undefined
     */
    function min(array) {
      return (array && array.length)
        ? baseExtremum(array, identity, baseLt)
        : undefined;
    }

    /**
     * This method is like `_.min` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the criterion by which
     * the value is ranked. The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {*} Returns the minimum value.
     * @example
     *
     * var objects = [{ 'n': 1 }, { 'n': 2 }];
     *
     * _.minBy(objects, function(o) { return o.n; });
     * // => { 'n': 1 }
     *
     * // The `_.property` iteratee shorthand.
     * _.minBy(objects, 'n');
     * // => { 'n': 1 }
     */
    function minBy(array, iteratee) {
      return (array && array.length)
        ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
        : undefined;
    }

    /**
     * Multiply two numbers.
     *
     * @static
     * @memberOf _
     * @since 4.7.0
     * @category Math
     * @param {number} multiplier The first number in a multiplication.
     * @param {number} multiplicand The second number in a multiplication.
     * @returns {number} Returns the product.
     * @example
     *
     * _.multiply(6, 4);
     * // => 24
     */
    var multiply = createMathOperation(function(multiplier, multiplicand) {
      return multiplier * multiplicand;
    }, 1);

    /**
     * Computes `number` rounded to `precision`.
     *
     * @static
     * @memberOf _
     * @since 3.10.0
     * @category Math
     * @param {number} number The number to round.
     * @param {number} [precision=0] The precision to round to.
     * @returns {number} Returns the rounded number.
     * @example
     *
     * _.round(4.006);
     * // => 4
     *
     * _.round(4.006, 2);
     * // => 4.01
     *
     * _.round(4060, -2);
     * // => 4100
     */
    var round = createRound('round');

    /**
     * Subtract two numbers.
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Math
     * @param {number} minuend The first number in a subtraction.
     * @param {number} subtrahend The second number in a subtraction.
     * @returns {number} Returns the difference.
     * @example
     *
     * _.subtract(6, 4);
     * // => 2
     */
    var subtract = createMathOperation(function(minuend, subtrahend) {
      return minuend - subtrahend;
    }, 0);

    /**
     * Computes the sum of the values in `array`.
     *
     * @static
     * @memberOf _
     * @since 3.4.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @returns {number} Returns the sum.
     * @example
     *
     * _.sum([4, 2, 8, 6]);
     * // => 20
     */
    function sum(array) {
      return (array && array.length)
        ? baseSum(array, identity)
        : 0;
    }

    /**
     * This method is like `_.sum` except that it accepts `iteratee` which is
     * invoked for each element in `array` to generate the value to be summed.
     * The iteratee is invoked with one argument: (value).
     *
     * @static
     * @memberOf _
     * @since 4.0.0
     * @category Math
     * @param {Array} array The array to iterate over.
     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
     * @returns {number} Returns the sum.
     * @example
     *
     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
     *
     * _.sumBy(objects, function(o) { return o.n; });
     * // => 20
     *
     * // The `_.property` iteratee shorthand.
     * _.sumBy(objects, 'n');
     * // => 20
     */
    function sumBy(array, iteratee) {
      return (array && array.length)
        ? baseSum(array, getIteratee(iteratee, 2))
        : 0;
    }

    /*------------------------------------------------------------------------*/

    // Add methods that return wrapped values in chain sequences.
    lodash.after = after;
    lodash.ary = ary;
    lodash.assign = assign;
    lodash.assignIn = assignIn;
    lodash.assignInWith = assignInWith;
    lodash.assignWith = assignWith;
    lodash.at = at;
    lodash.before = before;
    lodash.bind = bind;
    lodash.bindAll = bindAll;
    lodash.bindKey = bindKey;
    lodash.castArray = castArray;
    lodash.chain = chain;
    lodash.chunk = chunk;
    lodash.compact = compact;
    lodash.concat = concat;
    lodash.cond = cond;
    lodash.conforms = conforms;
    lodash.constant = constant;
    lodash.countBy = countBy;
    lodash.create = create;
    lodash.curry = curry;
    lodash.curryRight = curryRight;
    lodash.debounce = debounce;
    lodash.defaults = defaults;
    lodash.defaultsDeep = defaultsDeep;
    lodash.defer = defer;
    lodash.delay = delay;
    lodash.difference = difference;
    lodash.differenceBy = differenceBy;
    lodash.differenceWith = differenceWith;
    lodash.drop = drop;
    lodash.dropRight = dropRight;
    lodash.dropRightWhile = dropRightWhile;
    lodash.dropWhile = dropWhile;
    lodash.fill = fill;
    lodash.filter = filter;
    lodash.flatMap = flatMap;
    lodash.flatMapDeep = flatMapDeep;
    lodash.flatMapDepth = flatMapDepth;
    lodash.flatten = flatten;
    lodash.flattenDeep = flattenDeep;
    lodash.flattenDepth = flattenDepth;
    lodash.flip = flip;
    lodash.flow = flow;
    lodash.flowRight = flowRight;
    lodash.fromPairs = fromPairs;
    lodash.functions = functions;
    lodash.functionsIn = functionsIn;
    lodash.groupBy = groupBy;
    lodash.initial = initial;
    lodash.intersection = intersection;
    lodash.intersectionBy = intersectionBy;
    lodash.intersectionWith = intersectionWith;
    lodash.invert = invert;
    lodash.invertBy = invertBy;
    lodash.invokeMap = invokeMap;
    lodash.iteratee = iteratee;
    lodash.keyBy = keyBy;
    lodash.keys = keys;
    lodash.keysIn = keysIn;
    lodash.map = map;
    lodash.mapKeys = mapKeys;
    lodash.mapValues = mapValues;
    lodash.matches = matches;
    lodash.matchesProperty = matchesProperty;
    lodash.memoize = memoize;
    lodash.merge = merge;
    lodash.mergeWith = mergeWith;
    lodash.method = method;
    lodash.methodOf = methodOf;
    lodash.mixin = mixin;
    lodash.negate = negate;
    lodash.nthArg = nthArg;
    lodash.omit = omit;
    lodash.omitBy = omitBy;
    lodash.once = once;
    lodash.orderBy = orderBy;
    lodash.over = over;
    lodash.overArgs = overArgs;
    lodash.overEvery = overEvery;
    lodash.overSome = overSome;
    lodash.partial = partial;
    lodash.partialRight = partialRight;
    lodash.partition = partition;
    lodash.pick = pick;
    lodash.pickBy = pickBy;
    lodash.property = property;
    lodash.propertyOf = propertyOf;
    lodash.pull = pull;
    lodash.pullAll = pullAll;
    lodash.pullAllBy = pullAllBy;
    lodash.pullAllWith = pullAllWith;
    lodash.pullAt = pullAt;
    lodash.range = range;
    lodash.rangeRight = rangeRight;
    lodash.rearg = rearg;
    lodash.reject = reject;
    lodash.remove = remove;
    lodash.rest = rest;
    lodash.reverse = reverse;
    lodash.sampleSize = sampleSize;
    lodash.set = set;
    lodash.setWith = setWith;
    lodash.shuffle = shuffle;
    lodash.slice = slice;
    lodash.sortBy = sortBy;
    lodash.sortedUniq = sortedUniq;
    lodash.sortedUniqBy = sortedUniqBy;
    lodash.split = split;
    lodash.spread = spread;
    lodash.tail = tail;
    lodash.take = take;
    lodash.takeRight = takeRight;
    lodash.takeRightWhile = takeRightWhile;
    lodash.takeWhile = takeWhile;
    lodash.tap = tap;
    lodash.throttle = throttle;
    lodash.thru = thru;
    lodash.toArray = toArray;
    lodash.toPairs = toPairs;
    lodash.toPairsIn = toPairsIn;
    lodash.toPath = toPath;
    lodash.toPlainObject = toPlainObject;
    lodash.transform = transform;
    lodash.unary = unary;
    lodash.union = union;
    lodash.unionBy = unionBy;
    lodash.unionWith = unionWith;
    lodash.uniq = uniq;
    lodash.uniqBy = uniqBy;
    lodash.uniqWith = uniqWith;
    lodash.unset = unset;
    lodash.unzip = unzip;
    lodash.unzipWith = unzipWith;
    lodash.update = update;
    lodash.updateWith = updateWith;
    lodash.values = values;
    lodash.valuesIn = valuesIn;
    lodash.without = without;
    lodash.words = words;
    lodash.wrap = wrap;
    lodash.xor = xor;
    lodash.xorBy = xorBy;
    lodash.xorWith = xorWith;
    lodash.zip = zip;
    lodash.zipObject = zipObject;
    lodash.zipObjectDeep = zipObjectDeep;
    lodash.zipWith = zipWith;

    // Add aliases.
    lodash.entries = toPairs;
    lodash.entriesIn = toPairsIn;
    lodash.extend = assignIn;
    lodash.extendWith = assignInWith;

    // Add methods to `lodash.prototype`.
    mixin(lodash, lodash);

    /*------------------------------------------------------------------------*/

    // Add methods that return unwrapped values in chain sequences.
    lodash.add = add;
    lodash.attempt = attempt;
    lodash.camelCase = camelCase;
    lodash.capitalize = capitalize;
    lodash.ceil = ceil;
    lodash.clamp = clamp;
    lodash.clone = clone;
    lodash.cloneDeep = cloneDeep;
    lodash.cloneDeepWith = cloneDeepWith;
    lodash.cloneWith = cloneWith;
    lodash.conformsTo = conformsTo;
    lodash.deburr = deburr;
    lodash.defaultTo = defaultTo;
    lodash.divide = divide;
    lodash.endsWith = endsWith;
    lodash.eq = eq;
    lodash.escape = escape;
    lodash.escapeRegExp = escapeRegExp;
    lodash.every = every;
    lodash.find = find;
    lodash.findIndex = findIndex;
    lodash.findKey = findKey;
    lodash.findLast = findLast;
    lodash.findLastIndex = findLastIndex;
    lodash.findLastKey = findLastKey;
    lodash.floor = floor;
    lodash.forEach = forEach;
    lodash.forEachRight = forEachRight;
    lodash.forIn = forIn;
    lodash.forInRight = forInRight;
    lodash.forOwn = forOwn;
    lodash.forOwnRight = forOwnRight;
    lodash.get = get;
    lodash.gt = gt;
    lodash.gte = gte;
    lodash.has = has;
    lodash.hasIn = hasIn;
    lodash.head = head;
    lodash.identity = identity;
    lodash.includes = includes;
    lodash.indexOf = indexOf;
    lodash.inRange = inRange;
    lodash.invoke = invoke;
    lodash.isArguments = isArguments;
    lodash.isArray = isArray;
    lodash.isArrayBuffer = isArrayBuffer;
    lodash.isArrayLike = isArrayLike;
    lodash.isArrayLikeObject = isArrayLikeObject;
    lodash.isBoolean = isBoolean;
    lodash.isBuffer = isBuffer;
    lodash.isDate = isDate;
    lodash.isElement = isElement;
    lodash.isEmpty = isEmpty;
    lodash.isEqual = isEqual;
    lodash.isEqualWith = isEqualWith;
    lodash.isError = isError;
    lodash.isFinite = isFinite;
    lodash.isFunction = isFunction;
    lodash.isInteger = isInteger;
    lodash.isLength = isLength;
    lodash.isMap = isMap;
    lodash.isMatch = isMatch;
    lodash.isMatchWith = isMatchWith;
    lodash.isNaN = isNaN;
    lodash.isNative = isNative;
    lodash.isNil = isNil;
    lodash.isNull = isNull;
    lodash.isNumber = isNumber;
    lodash.isObject = isObject;
    lodash.isObjectLike = isObjectLike;
    lodash.isPlainObject = isPlainObject;
    lodash.isRegExp = isRegExp;
    lodash.isSafeInteger = isSafeInteger;
    lodash.isSet = isSet;
    lodash.isString = isString;
    lodash.isSymbol = isSymbol;
    lodash.isTypedArray = isTypedArray;
    lodash.isUndefined = isUndefined;
    lodash.isWeakMap = isWeakMap;
    lodash.isWeakSet = isWeakSet;
    lodash.join = join;
    lodash.kebabCase = kebabCase;
    lodash.last = last;
    lodash.lastIndexOf = lastIndexOf;
    lodash.lowerCase = lowerCase;
    lodash.lowerFirst = lowerFirst;
    lodash.lt = lt;
    lodash.lte = lte;
    lodash.max = max;
    lodash.maxBy = maxBy;
    lodash.mean = mean;
    lodash.meanBy = meanBy;
    lodash.min = min;
    lodash.minBy = minBy;
    lodash.stubArray = stubArray;
    lodash.stubFalse = stubFalse;
    lodash.stubObject = stubObject;
    lodash.stubString = stubString;
    lodash.stubTrue = stubTrue;
    lodash.multiply = multiply;
    lodash.nth = nth;
    lodash.noConflict = noConflict;
    lodash.noop = noop;
    lodash.now = now;
    lodash.pad = pad;
    lodash.padEnd = padEnd;
    lodash.padStart = padStart;
    lodash.parseInt = parseInt;
    lodash.random = random;
    lodash.reduce = reduce;
    lodash.reduceRight = reduceRight;
    lodash.repeat = repeat;
    lodash.replace = replace;
    lodash.result = result;
    lodash.round = round;
    lodash.runInContext = runInContext;
    lodash.sample = sample;
    lodash.size = size;
    lodash.snakeCase = snakeCase;
    lodash.some = some;
    lodash.sortedIndex = sortedIndex;
    lodash.sortedIndexBy = sortedIndexBy;
    lodash.sortedIndexOf = sortedIndexOf;
    lodash.sortedLastIndex = sortedLastIndex;
    lodash.sortedLastIndexBy = sortedLastIndexBy;
    lodash.sortedLastIndexOf = sortedLastIndexOf;
    lodash.startCase = startCase;
    lodash.startsWith = startsWith;
    lodash.subtract = subtract;
    lodash.sum = sum;
    lodash.sumBy = sumBy;
    lodash.template = template;
    lodash.times = times;
    lodash.toFinite = toFinite;
    lodash.toInteger = toInteger;
    lodash.toLength = toLength;
    lodash.toLower = toLower;
    lodash.toNumber = toNumber;
    lodash.toSafeInteger = toSafeInteger;
    lodash.toString = toString;
    lodash.toUpper = toUpper;
    lodash.trim = trim;
    lodash.trimEnd = trimEnd;
    lodash.trimStart = trimStart;
    lodash.truncate = truncate;
    lodash.unescape = unescape;
    lodash.uniqueId = uniqueId;
    lodash.upperCase = upperCase;
    lodash.upperFirst = upperFirst;

    // Add aliases.
    lodash.each = forEach;
    lodash.eachRight = forEachRight;
    lodash.first = head;

    mixin(lodash, (function() {
      var source = {};
      baseForOwn(lodash, function(func, methodName) {
        if (!hasOwnProperty.call(lodash.prototype, methodName)) {
          source[methodName] = func;
        }
      });
      return source;
    }()), { 'chain': false });

    /*------------------------------------------------------------------------*/

    /**
     * The semantic version number.
     *
     * @static
     * @memberOf _
     * @type {string}
     */
    lodash.VERSION = VERSION;

    // Assign default placeholders.
    arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
      lodash[methodName].placeholder = lodash;
    });

    // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
    arrayEach(['drop', 'take'], function(methodName, index) {
      LazyWrapper.prototype[methodName] = function(n) {
        n = n === undefined ? 1 : nativeMax(toInteger(n), 0);

        var result = (this.__filtered__ && !index)
          ? new LazyWrapper(this)
          : this.clone();

        if (result.__filtered__) {
          result.__takeCount__ = nativeMin(n, result.__takeCount__);
        } else {
          result.__views__.push({
            'size': nativeMin(n, MAX_ARRAY_LENGTH),
            'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
          });
        }
        return result;
      };

      LazyWrapper.prototype[methodName + 'Right'] = function(n) {
        return this.reverse()[methodName](n).reverse();
      };
    });

    // Add `LazyWrapper` methods that accept an `iteratee` value.
    arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
      var type = index + 1,
          isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;

      LazyWrapper.prototype[methodName] = function(iteratee) {
        var result = this.clone();
        result.__iteratees__.push({
          'iteratee': getIteratee(iteratee, 3),
          'type': type
        });
        result.__filtered__ = result.__filtered__ || isFilter;
        return result;
      };
    });

    // Add `LazyWrapper` methods for `_.head` and `_.last`.
    arrayEach(['head', 'last'], function(methodName, index) {
      var takeName = 'take' + (index ? 'Right' : '');

      LazyWrapper.prototype[methodName] = function() {
        return this[takeName](1).value()[0];
      };
    });

    // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
    arrayEach(['initial', 'tail'], function(methodName, index) {
      var dropName = 'drop' + (index ? '' : 'Right');

      LazyWrapper.prototype[methodName] = function() {
        return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
      };
    });

    LazyWrapper.prototype.compact = function() {
      return this.filter(identity);
    };

    LazyWrapper.prototype.find = function(predicate) {
      return this.filter(predicate).head();
    };

    LazyWrapper.prototype.findLast = function(predicate) {
      return this.reverse().find(predicate);
    };

    LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
      if (typeof path == 'function') {
        return new LazyWrapper(this);
      }
      return this.map(function(value) {
        return baseInvoke(value, path, args);
      });
    });

    LazyWrapper.prototype.reject = function(predicate) {
      return this.filter(negate(getIteratee(predicate)));
    };

    LazyWrapper.prototype.slice = function(start, end) {
      start = toInteger(start);

      var result = this;
      if (result.__filtered__ && (start > 0 || end < 0)) {
        return new LazyWrapper(result);
      }
      if (start < 0) {
        result = result.takeRight(-start);
      } else if (start) {
        result = result.drop(start);
      }
      if (end !== undefined) {
        end = toInteger(end);
        result = end < 0 ? result.dropRight(-end) : result.take(end - start);
      }
      return result;
    };

    LazyWrapper.prototype.takeRightWhile = function(predicate) {
      return this.reverse().takeWhile(predicate).reverse();
    };

    LazyWrapper.prototype.toArray = function() {
      return this.take(MAX_ARRAY_LENGTH);
    };

    // Add `LazyWrapper` methods to `lodash.prototype`.
    baseForOwn(LazyWrapper.prototype, function(func, methodName) {
      var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
          isTaker = /^(?:head|last)$/.test(methodName),
          lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
          retUnwrapped = isTaker || /^find/.test(methodName);

      if (!lodashFunc) {
        return;
      }
      lodash.prototype[methodName] = function() {
        var value = this.__wrapped__,
            args = isTaker ? [1] : arguments,
            isLazy = value instanceof LazyWrapper,
            iteratee = args[0],
            useLazy = isLazy || isArray(value);

        var interceptor = function(value) {
          var result = lodashFunc.apply(lodash, arrayPush([value], args));
          return (isTaker && chainAll) ? result[0] : result;
        };

        if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
          // Avoid lazy use if the iteratee has a "length" value other than `1`.
          isLazy = useLazy = false;
        }
        var chainAll = this.__chain__,
            isHybrid = !!this.__actions__.length,
            isUnwrapped = retUnwrapped && !chainAll,
            onlyLazy = isLazy && !isHybrid;

        if (!retUnwrapped && useLazy) {
          value = onlyLazy ? value : new LazyWrapper(this);
          var result = func.apply(value, args);
          result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
          return new LodashWrapper(result, chainAll);
        }
        if (isUnwrapped && onlyLazy) {
          return func.apply(this, args);
        }
        result = this.thru(interceptor);
        return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
      };
    });

    // Add `Array` methods to `lodash.prototype`.
    arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
      var func = arrayProto[methodName],
          chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
          retUnwrapped = /^(?:pop|shift)$/.test(methodName);

      lodash.prototype[methodName] = function() {
        var args = arguments;
        if (retUnwrapped && !this.__chain__) {
          var value = this.value();
          return func.apply(isArray(value) ? value : [], args);
        }
        return this[chainName](function(value) {
          return func.apply(isArray(value) ? value : [], args);
        });
      };
    });

    // Map minified method names to their real names.
    baseForOwn(LazyWrapper.prototype, function(func, methodName) {
      var lodashFunc = lodash[methodName];
      if (lodashFunc) {
        var key = lodashFunc.name + '';
        if (!hasOwnProperty.call(realNames, key)) {
          realNames[key] = [];
        }
        realNames[key].push({ 'name': methodName, 'func': lodashFunc });
      }
    });

    realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
      'name': 'wrapper',
      'func': undefined
    }];

    // Add methods to `LazyWrapper`.
    LazyWrapper.prototype.clone = lazyClone;
    LazyWrapper.prototype.reverse = lazyReverse;
    LazyWrapper.prototype.value = lazyValue;

    // Add chain sequence methods to the `lodash` wrapper.
    lodash.prototype.at = wrapperAt;
    lodash.prototype.chain = wrapperChain;
    lodash.prototype.commit = wrapperCommit;
    lodash.prototype.next = wrapperNext;
    lodash.prototype.plant = wrapperPlant;
    lodash.prototype.reverse = wrapperReverse;
    lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;

    // Add lazy aliases.
    lodash.prototype.first = lodash.prototype.head;

    if (symIterator) {
      lodash.prototype[symIterator] = wrapperToIterator;
    }
    return lodash;
  });

  /*--------------------------------------------------------------------------*/

  // Export lodash.
  var _ = runInContext();

  // Some AMD build optimizers, like r.js, check for condition patterns like:
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
    // Expose Lodash on the global object to prevent errors when Lodash is
    // loaded by a script tag in the presence of an AMD loader.
    // See http://requirejs.org/docs/errors.html#mismatch for more details.
    // Use `_.noConflict` to remove Lodash from the global object.
    root._ = _;

    // Define as an anonymous module so, through path mapping, it can be
    // referenced as the "underscore" module.
    define(function() {
      return _;
    });
  }
  // Check for `exports` after `define` in case a build optimizer adds it.
  else if (freeModule) {
    // Export for Node.js.
    (freeModule.exports = _)._ = _;
    // Export for CommonJS support.
    freeExports._ = _;
  }
  else {
    // Export to the global object.
    root._ = _;
  }
}.call(this));

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})

},{}],217:[function(require,module,exports){
/*!
 * Masonry v4.2.2
 * Cascading grid layout library
 * https://masonry.desandro.com
 * MIT License
 * by David DeSandro
 */

( function( window, factory ) {
  // universal module definition
  /* jshint strict: false */ /*globals define, module, require */
  if ( typeof define == 'function' && define.amd ) {
    // AMD
    define( [
        'outlayer/outlayer',
        'get-size/get-size'
      ],
      factory );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS
    module.exports = factory(
      require('outlayer'),
      require('get-size')
    );
  } else {
    // browser global
    window.Masonry = factory(
      window.Outlayer,
      window.getSize
    );
  }

}( window, function factory( Outlayer, getSize ) {

'use strict';

// -------------------------- masonryDefinition -------------------------- //

  // create an Outlayer layout class
  var Masonry = Outlayer.create('masonry');
  // isFitWidth -> fitWidth
  Masonry.compatOptions.fitWidth = 'isFitWidth';

  var proto = Masonry.prototype;

  proto._resetLayout = function() {
    this.getSize();
    this._getMeasurement( 'columnWidth', 'outerWidth' );
    this._getMeasurement( 'gutter', 'outerWidth' );
    this.measureColumns();

    // reset column Y
    this.colYs = [];
    for ( var i=0; i < this.cols; i++ ) {
      this.colYs.push( 0 );
    }

    this.maxY = 0;
    this.horizontalColIndex = 0;
  };

  proto.measureColumns = function() {
    this.getContainerWidth();
    // if columnWidth is 0, default to outerWidth of first item
    if ( !this.columnWidth ) {
      var firstItem = this.items[0];
      var firstItemElem = firstItem && firstItem.element;
      // columnWidth fall back to item of first element
      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
        // if first elem has no width, default to size of container
        this.containerWidth;
    }

    var columnWidth = this.columnWidth += this.gutter;

    // calculate columns
    var containerWidth = this.containerWidth + this.gutter;
    var cols = containerWidth / columnWidth;
    // fix rounding errors, typically with gutters
    var excess = columnWidth - containerWidth % columnWidth;
    // if overshoot is less than a pixel, round up, otherwise floor it
    var mathMethod = excess && excess < 1 ? 'round' : 'floor';
    cols = Math[ mathMethod ]( cols );
    this.cols = Math.max( cols, 1 );
  };

  proto.getContainerWidth = function() {
    // container is parent if fit width
    var isFitWidth = this._getOption('fitWidth');
    var container = isFitWidth ? this.element.parentNode : this.element;
    // check that this.size and size are there
    // IE8 triggers resize on body size change, so they might not be
    var size = getSize( container );
    this.containerWidth = size && size.innerWidth;
  };

  proto._getItemLayoutPosition = function( item ) {
    item.getSize();
    // how many columns does this brick span
    var remainder = item.size.outerWidth % this.columnWidth;
    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
    // round if off by 1 pixel, otherwise use ceil
    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
    colSpan = Math.min( colSpan, this.cols );
    // use horizontal or top column position
    var colPosMethod = this.options.horizontalOrder ?
      '_getHorizontalColPosition' : '_getTopColPosition';
    var colPosition = this[ colPosMethod ]( colSpan, item );
    // position the brick
    var position = {
      x: this.columnWidth * colPosition.col,
      y: colPosition.y
    };
    // apply setHeight to necessary columns
    var setHeight = colPosition.y + item.size.outerHeight;
    var setMax = colSpan + colPosition.col;
    for ( var i = colPosition.col; i < setMax; i++ ) {
      this.colYs[i] = setHeight;
    }

    return position;
  };

  proto._getTopColPosition = function( colSpan ) {
    var colGroup = this._getTopColGroup( colSpan );
    // get the minimum Y value from the columns
    var minimumY = Math.min.apply( Math, colGroup );

    return {
      col: colGroup.indexOf( minimumY ),
      y: minimumY,
    };
  };

  /**
   * @param {Number} colSpan - number of columns the element spans
   * @returns {Array} colGroup
   */
  proto._getTopColGroup = function( colSpan ) {
    if ( colSpan < 2 ) {
      // if brick spans only one column, use all the column Ys
      return this.colYs;
    }

    var colGroup = [];
    // how many different places could this brick fit horizontally
    var groupCount = this.cols + 1 - colSpan;
    // for each group potential horizontal position
    for ( var i = 0; i < groupCount; i++ ) {
      colGroup[i] = this._getColGroupY( i, colSpan );
    }
    return colGroup;
  };

  proto._getColGroupY = function( col, colSpan ) {
    if ( colSpan < 2 ) {
      return this.colYs[ col ];
    }
    // make an array of colY values for that one group
    var groupColYs = this.colYs.slice( col, col + colSpan );
    // and get the max value of the array
    return Math.max.apply( Math, groupColYs );
  };

  // get column position based on horizontal index. #873
  proto._getHorizontalColPosition = function( colSpan, item ) {
    var col = this.horizontalColIndex % this.cols;
    var isOver = colSpan > 1 && col + colSpan > this.cols;
    // shift to next row if item can't fit on current row
    col = isOver ? 0 : col;
    // don't let zero-size items take up space
    var hasSize = item.size.outerWidth && item.size.outerHeight;
    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;

    return {
      col: col,
      y: this._getColGroupY( col, colSpan ),
    };
  };

  proto._manageStamp = function( stamp ) {
    var stampSize = getSize( stamp );
    var offset = this._getElementOffset( stamp );
    // get the columns that this stamp affects
    var isOriginLeft = this._getOption('originLeft');
    var firstX = isOriginLeft ? offset.left : offset.right;
    var lastX = firstX + stampSize.outerWidth;
    var firstCol = Math.floor( firstX / this.columnWidth );
    firstCol = Math.max( 0, firstCol );
    var lastCol = Math.floor( lastX / this.columnWidth );
    // lastCol should not go over if multiple of columnWidth #425
    lastCol -= lastX % this.columnWidth ? 0 : 1;
    lastCol = Math.min( this.cols - 1, lastCol );
    // set colYs to bottom of the stamp

    var isOriginTop = this._getOption('originTop');
    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
      stampSize.outerHeight;
    for ( var i = firstCol; i <= lastCol; i++ ) {
      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
    }
  };

  proto._getContainerSize = function() {
    this.maxY = Math.max.apply( Math, this.colYs );
    var size = {
      height: this.maxY
    };

    if ( this._getOption('fitWidth') ) {
      size.width = this._getContainerFitWidth();
    }

    return size;
  };

  proto._getContainerFitWidth = function() {
    var unusedCols = 0;
    // count unused columns
    var i = this.cols;
    while ( --i ) {
      if ( this.colYs[i] !== 0 ) {
        break;
      }
      unusedCols++;
    }
    // fit container to columns that have been used
    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
  };

  proto.needsResizeLayout = function() {
    var previousWidth = this.containerWidth;
    this.getContainerWidth();
    return previousWidth != this.containerWidth;
  };

  return Masonry;

}));

},{"get-size":209,"outlayer":222}],218:[function(require,module,exports){
//! moment.js locale configuration
//! locale : Russian [ru]
//! author : Viktorminator : https://github.com/Viktorminator
//! author : Menelion Elensúle : https://github.com/Oire
//! author : Коренберг Марк : https://github.com/socketpair

;(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined'
       && typeof require === 'function' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['../moment'], factory) :
   factory(global.moment)
}(this, (function (moment) { 'use strict';

    //! moment.js locale configuration

    function plural(word, num) {
        var forms = word.split('_');
        return num % 10 === 1 && num % 100 !== 11
            ? forms[0]
            : num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20)
            ? forms[1]
            : forms[2];
    }
    function relativeTimeWithPlural(number, withoutSuffix, key) {
        var format = {
            ss: withoutSuffix ? 'секунда_секунды_секунд' : 'секунду_секунды_секунд',
            mm: withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',
            hh: 'час_часа_часов',
            dd: 'день_дня_дней',
            MM: 'месяц_месяца_месяцев',
            yy: 'год_года_лет',
        };
        if (key === 'm') {
            return withoutSuffix ? 'минута' : 'минуту';
        } else {
            return number + ' ' + plural(format[key], +number);
        }
    }
    var monthsParse = [
        /^янв/i,
        /^фев/i,
        /^мар/i,
        /^апр/i,
        /^ма[йя]/i,
        /^июн/i,
        /^июл/i,
        /^авг/i,
        /^сен/i,
        /^окт/i,
        /^ноя/i,
        /^дек/i,
    ];

    // http://new.gramota.ru/spravka/rules/139-prop : § 103
    // Сокращения месяцев: http://new.gramota.ru/spravka/buro/search-answer?s=242637
    // CLDR data:          http://www.unicode.org/cldr/charts/28/summary/ru.html#1753
    var ru = moment.defineLocale('ru', {
        months: {
            format: 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split(
                '_'
            ),
            standalone: 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split(
                '_'
            ),
        },
        monthsShort: {
            // по CLDR именно "июл." и "июн.", но какой смысл менять букву на точку?
            format: 'янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.'.split(
                '_'
            ),
            standalone: 'янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.'.split(
                '_'
            ),
        },
        weekdays: {
            standalone: 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split(
                '_'
            ),
            format: 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split(
                '_'
            ),
            isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/,
        },
        weekdaysShort: 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        weekdaysMin: 'вс_пн_вт_ср_чт_пт_сб'.split('_'),
        monthsParse: monthsParse,
        longMonthsParse: monthsParse,
        shortMonthsParse: monthsParse,

        // полные названия с падежами, по три буквы, для некоторых, по 4 буквы, сокращения с точкой и без точки
        monthsRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,

        // копия предыдущего
        monthsShortRegex: /^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,

        // полные названия с падежами
        monthsStrictRegex: /^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,

        // Выражение, которое соответствует только сокращённым формам
        monthsShortStrictRegex: /^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,
        longDateFormat: {
            LT: 'H:mm',
            LTS: 'H:mm:ss',
            L: 'DD.MM.YYYY',
            LL: 'D MMMM YYYY г.',
            LLL: 'D MMMM YYYY г., H:mm',
            LLLL: 'dddd, D MMMM YYYY г., H:mm',
        },
        calendar: {
            sameDay: '[Сегодня, в] LT',
            nextDay: '[Завтра, в] LT',
            lastDay: '[Вчера, в] LT',
            nextWeek: function (now) {
                if (now.week() !== this.week()) {
                    switch (this.day()) {
                        case 0:
                            return '[В следующее] dddd, [в] LT';
                        case 1:
                        case 2:
                        case 4:
                            return '[В следующий] dddd, [в] LT';
                        case 3:
                        case 5:
                        case 6:
                            return '[В следующую] dddd, [в] LT';
                    }
                } else {
                    if (this.day() === 2) {
                        return '[Во] dddd, [в] LT';
                    } else {
                        return '[В] dddd, [в] LT';
                    }
                }
            },
            lastWeek: function (now) {
                if (now.week() !== this.week()) {
                    switch (this.day()) {
                        case 0:
                            return '[В прошлое] dddd, [в] LT';
                        case 1:
                        case 2:
                        case 4:
                            return '[В прошлый] dddd, [в] LT';
                        case 3:
                        case 5:
                        case 6:
                            return '[В прошлую] dddd, [в] LT';
                    }
                } else {
                    if (this.day() === 2) {
                        return '[Во] dddd, [в] LT';
                    } else {
                        return '[В] dddd, [в] LT';
                    }
                }
            },
            sameElse: 'L',
        },
        relativeTime: {
            future: 'через %s',
            past: '%s назад',
            s: 'несколько секунд',
            ss: relativeTimeWithPlural,
            m: relativeTimeWithPlural,
            mm: relativeTimeWithPlural,
            h: 'час',
            hh: relativeTimeWithPlural,
            d: 'день',
            dd: relativeTimeWithPlural,
            M: 'месяц',
            MM: relativeTimeWithPlural,
            y: 'год',
            yy: relativeTimeWithPlural,
        },
        meridiemParse: /ночи|утра|дня|вечера/i,
        isPM: function (input) {
            return /^(дня|вечера)$/.test(input);
        },
        meridiem: function (hour, minute, isLower) {
            if (hour < 4) {
                return 'ночи';
            } else if (hour < 12) {
                return 'утра';
            } else if (hour < 17) {
                return 'дня';
            } else {
                return 'вечера';
            }
        },
        dayOfMonthOrdinalParse: /\d{1,2}-(й|го|я)/,
        ordinal: function (number, period) {
            switch (period) {
                case 'M':
                case 'd':
                case 'DDD':
                    return number + '-й';
                case 'D':
                    return number + '-го';
                case 'w':
                case 'W':
                    return number + '-я';
                default:
                    return number;
            }
        },
        week: {
            dow: 1, // Monday is the first day of the week.
            doy: 4, // The week that contains Jan 4th is the first week of the year.
        },
    });

    return ru;

})));

},{"../moment":219}],219:[function(require,module,exports){
//! moment.js
//! version : 2.27.0
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com

;(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    global.moment = factory()
}(this, (function () { 'use strict';

    var hookCallback;

    function hooks() {
        return hookCallback.apply(null, arguments);
    }

    // This is done to register the method called with moment()
    // without creating circular dependencies.
    function setHookCallback(callback) {
        hookCallback = callback;
    }

    function isArray(input) {
        return (
            input instanceof Array ||
            Object.prototype.toString.call(input) === '[object Array]'
        );
    }

    function isObject(input) {
        // IE8 will treat undefined and null as object if it wasn't for
        // input != null
        return (
            input != null &&
            Object.prototype.toString.call(input) === '[object Object]'
        );
    }

    function hasOwnProp(a, b) {
        return Object.prototype.hasOwnProperty.call(a, b);
    }

    function isObjectEmpty(obj) {
        if (Object.getOwnPropertyNames) {
            return Object.getOwnPropertyNames(obj).length === 0;
        } else {
            var k;
            for (k in obj) {
                if (hasOwnProp(obj, k)) {
                    return false;
                }
            }
            return true;
        }
    }

    function isUndefined(input) {
        return input === void 0;
    }

    function isNumber(input) {
        return (
            typeof input === 'number' ||
            Object.prototype.toString.call(input) === '[object Number]'
        );
    }

    function isDate(input) {
        return (
            input instanceof Date ||
            Object.prototype.toString.call(input) === '[object Date]'
        );
    }

    function map(arr, fn) {
        var res = [],
            i;
        for (i = 0; i < arr.length; ++i) {
            res.push(fn(arr[i], i));
        }
        return res;
    }

    function extend(a, b) {
        for (var i in b) {
            if (hasOwnProp(b, i)) {
                a[i] = b[i];
            }
        }

        if (hasOwnProp(b, 'toString')) {
            a.toString = b.toString;
        }

        if (hasOwnProp(b, 'valueOf')) {
            a.valueOf = b.valueOf;
        }

        return a;
    }

    function createUTC(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, true).utc();
    }

    function defaultParsingFlags() {
        // We need to deep clone this object.
        return {
            empty: false,
            unusedTokens: [],
            unusedInput: [],
            overflow: -2,
            charsLeftOver: 0,
            nullInput: false,
            invalidEra: null,
            invalidMonth: null,
            invalidFormat: false,
            userInvalidated: false,
            iso: false,
            parsedDateParts: [],
            era: null,
            meridiem: null,
            rfc2822: false,
            weekdayMismatch: false,
        };
    }

    function getParsingFlags(m) {
        if (m._pf == null) {
            m._pf = defaultParsingFlags();
        }
        return m._pf;
    }

    var some;
    if (Array.prototype.some) {
        some = Array.prototype.some;
    } else {
        some = function (fun) {
            var t = Object(this),
                len = t.length >>> 0,
                i;

            for (i = 0; i < len; i++) {
                if (i in t && fun.call(this, t[i], i, t)) {
                    return true;
                }
            }

            return false;
        };
    }

    function isValid(m) {
        if (m._isValid == null) {
            var flags = getParsingFlags(m),
                parsedParts = some.call(flags.parsedDateParts, function (i) {
                    return i != null;
                }),
                isNowValid =
                    !isNaN(m._d.getTime()) &&
                    flags.overflow < 0 &&
                    !flags.empty &&
                    !flags.invalidEra &&
                    !flags.invalidMonth &&
                    !flags.invalidWeekday &&
                    !flags.weekdayMismatch &&
                    !flags.nullInput &&
                    !flags.invalidFormat &&
                    !flags.userInvalidated &&
                    (!flags.meridiem || (flags.meridiem && parsedParts));

            if (m._strict) {
                isNowValid =
                    isNowValid &&
                    flags.charsLeftOver === 0 &&
                    flags.unusedTokens.length === 0 &&
                    flags.bigHour === undefined;
            }

            if (Object.isFrozen == null || !Object.isFrozen(m)) {
                m._isValid = isNowValid;
            } else {
                return isNowValid;
            }
        }
        return m._isValid;
    }

    function createInvalid(flags) {
        var m = createUTC(NaN);
        if (flags != null) {
            extend(getParsingFlags(m), flags);
        } else {
            getParsingFlags(m).userInvalidated = true;
        }

        return m;
    }

    // Plugins that add properties should also add the key here (null value),
    // so we can properly clone ourselves.
    var momentProperties = (hooks.momentProperties = []),
        updateInProgress = false;

    function copyConfig(to, from) {
        var i, prop, val;

        if (!isUndefined(from._isAMomentObject)) {
            to._isAMomentObject = from._isAMomentObject;
        }
        if (!isUndefined(from._i)) {
            to._i = from._i;
        }
        if (!isUndefined(from._f)) {
            to._f = from._f;
        }
        if (!isUndefined(from._l)) {
            to._l = from._l;
        }
        if (!isUndefined(from._strict)) {
            to._strict = from._strict;
        }
        if (!isUndefined(from._tzm)) {
            to._tzm = from._tzm;
        }
        if (!isUndefined(from._isUTC)) {
            to._isUTC = from._isUTC;
        }
        if (!isUndefined(from._offset)) {
            to._offset = from._offset;
        }
        if (!isUndefined(from._pf)) {
            to._pf = getParsingFlags(from);
        }
        if (!isUndefined(from._locale)) {
            to._locale = from._locale;
        }

        if (momentProperties.length > 0) {
            for (i = 0; i < momentProperties.length; i++) {
                prop = momentProperties[i];
                val = from[prop];
                if (!isUndefined(val)) {
                    to[prop] = val;
                }
            }
        }

        return to;
    }

    // Moment prototype object
    function Moment(config) {
        copyConfig(this, config);
        this._d = new Date(config._d != null ? config._d.getTime() : NaN);
        if (!this.isValid()) {
            this._d = new Date(NaN);
        }
        // Prevent infinite loop in case updateOffset creates new moment
        // objects.
        if (updateInProgress === false) {
            updateInProgress = true;
            hooks.updateOffset(this);
            updateInProgress = false;
        }
    }

    function isMoment(obj) {
        return (
            obj instanceof Moment || (obj != null && obj._isAMomentObject != null)
        );
    }

    function warn(msg) {
        if (
            hooks.suppressDeprecationWarnings === false &&
            typeof console !== 'undefined' &&
            console.warn
        ) {
            console.warn('Deprecation warning: ' + msg);
        }
    }

    function deprecate(msg, fn) {
        var firstTime = true;

        return extend(function () {
            if (hooks.deprecationHandler != null) {
                hooks.deprecationHandler(null, msg);
            }
            if (firstTime) {
                var args = [],
                    arg,
                    i,
                    key;
                for (i = 0; i < arguments.length; i++) {
                    arg = '';
                    if (typeof arguments[i] === 'object') {
                        arg += '\n[' + i + '] ';
                        for (key in arguments[0]) {
                            if (hasOwnProp(arguments[0], key)) {
                                arg += key + ': ' + arguments[0][key] + ', ';
                            }
                        }
                        arg = arg.slice(0, -2); // Remove trailing comma and space
                    } else {
                        arg = arguments[i];
                    }
                    args.push(arg);
                }
                warn(
                    msg +
                        '\nArguments: ' +
                        Array.prototype.slice.call(args).join('') +
                        '\n' +
                        new Error().stack
                );
                firstTime = false;
            }
            return fn.apply(this, arguments);
        }, fn);
    }

    var deprecations = {};

    function deprecateSimple(name, msg) {
        if (hooks.deprecationHandler != null) {
            hooks.deprecationHandler(name, msg);
        }
        if (!deprecations[name]) {
            warn(msg);
            deprecations[name] = true;
        }
    }

    hooks.suppressDeprecationWarnings = false;
    hooks.deprecationHandler = null;

    function isFunction(input) {
        return (
            (typeof Function !== 'undefined' && input instanceof Function) ||
            Object.prototype.toString.call(input) === '[object Function]'
        );
    }

    function set(config) {
        var prop, i;
        for (i in config) {
            if (hasOwnProp(config, i)) {
                prop = config[i];
                if (isFunction(prop)) {
                    this[i] = prop;
                } else {
                    this['_' + i] = prop;
                }
            }
        }
        this._config = config;
        // Lenient ordinal parsing accepts just a number in addition to
        // number + (possibly) stuff coming from _dayOfMonthOrdinalParse.
        // TODO: Remove "ordinalParse" fallback in next major release.
        this._dayOfMonthOrdinalParseLenient = new RegExp(
            (this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +
                '|' +
                /\d{1,2}/.source
        );
    }

    function mergeConfigs(parentConfig, childConfig) {
        var res = extend({}, parentConfig),
            prop;
        for (prop in childConfig) {
            if (hasOwnProp(childConfig, prop)) {
                if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
                    res[prop] = {};
                    extend(res[prop], parentConfig[prop]);
                    extend(res[prop], childConfig[prop]);
                } else if (childConfig[prop] != null) {
                    res[prop] = childConfig[prop];
                } else {
                    delete res[prop];
                }
            }
        }
        for (prop in parentConfig) {
            if (
                hasOwnProp(parentConfig, prop) &&
                !hasOwnProp(childConfig, prop) &&
                isObject(parentConfig[prop])
            ) {
                // make sure changes to properties don't modify parent config
                res[prop] = extend({}, res[prop]);
            }
        }
        return res;
    }

    function Locale(config) {
        if (config != null) {
            this.set(config);
        }
    }

    var keys;

    if (Object.keys) {
        keys = Object.keys;
    } else {
        keys = function (obj) {
            var i,
                res = [];
            for (i in obj) {
                if (hasOwnProp(obj, i)) {
                    res.push(i);
                }
            }
            return res;
        };
    }

    var defaultCalendar = {
        sameDay: '[Today at] LT',
        nextDay: '[Tomorrow at] LT',
        nextWeek: 'dddd [at] LT',
        lastDay: '[Yesterday at] LT',
        lastWeek: '[Last] dddd [at] LT',
        sameElse: 'L',
    };

    function calendar(key, mom, now) {
        var output = this._calendar[key] || this._calendar['sameElse'];
        return isFunction(output) ? output.call(mom, now) : output;
    }

    function zeroFill(number, targetLength, forceSign) {
        var absNumber = '' + Math.abs(number),
            zerosToFill = targetLength - absNumber.length,
            sign = number >= 0;
        return (
            (sign ? (forceSign ? '+' : '') : '-') +
            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) +
            absNumber
        );
    }

    var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,
        localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
        formatFunctions = {},
        formatTokenFunctions = {};

    // token:    'M'
    // padded:   ['MM', 2]
    // ordinal:  'Mo'
    // callback: function () { this.month() + 1 }
    function addFormatToken(token, padded, ordinal, callback) {
        var func = callback;
        if (typeof callback === 'string') {
            func = function () {
                return this[callback]();
            };
        }
        if (token) {
            formatTokenFunctions[token] = func;
        }
        if (padded) {
            formatTokenFunctions[padded[0]] = function () {
                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
            };
        }
        if (ordinal) {
            formatTokenFunctions[ordinal] = function () {
                return this.localeData().ordinal(
                    func.apply(this, arguments),
                    token
                );
            };
        }
    }

    function removeFormattingTokens(input) {
        if (input.match(/\[[\s\S]/)) {
            return input.replace(/^\[|\]$/g, '');
        }
        return input.replace(/\\/g, '');
    }

    function makeFormatFunction(format) {
        var array = format.match(formattingTokens),
            i,
            length;

        for (i = 0, length = array.length; i < length; i++) {
            if (formatTokenFunctions[array[i]]) {
                array[i] = formatTokenFunctions[array[i]];
            } else {
                array[i] = removeFormattingTokens(array[i]);
            }
        }

        return function (mom) {
            var output = '',
                i;
            for (i = 0; i < length; i++) {
                output += isFunction(array[i])
                    ? array[i].call(mom, format)
                    : array[i];
            }
            return output;
        };
    }

    // format date using native date object
    function formatMoment(m, format) {
        if (!m.isValid()) {
            return m.localeData().invalidDate();
        }

        format = expandFormat(format, m.localeData());
        formatFunctions[format] =
            formatFunctions[format] || makeFormatFunction(format);

        return formatFunctions[format](m);
    }

    function expandFormat(format, locale) {
        var i = 5;

        function replaceLongDateFormatTokens(input) {
            return locale.longDateFormat(input) || input;
        }

        localFormattingTokens.lastIndex = 0;
        while (i >= 0 && localFormattingTokens.test(format)) {
            format = format.replace(
                localFormattingTokens,
                replaceLongDateFormatTokens
            );
            localFormattingTokens.lastIndex = 0;
            i -= 1;
        }

        return format;
    }

    var defaultLongDateFormat = {
        LTS: 'h:mm:ss A',
        LT: 'h:mm A',
        L: 'MM/DD/YYYY',
        LL: 'MMMM D, YYYY',
        LLL: 'MMMM D, YYYY h:mm A',
        LLLL: 'dddd, MMMM D, YYYY h:mm A',
    };

    function longDateFormat(key) {
        var format = this._longDateFormat[key],
            formatUpper = this._longDateFormat[key.toUpperCase()];

        if (format || !formatUpper) {
            return format;
        }

        this._longDateFormat[key] = formatUpper
            .match(formattingTokens)
            .map(function (tok) {
                if (
                    tok === 'MMMM' ||
                    tok === 'MM' ||
                    tok === 'DD' ||
                    tok === 'dddd'
                ) {
                    return tok.slice(1);
                }
                return tok;
            })
            .join('');

        return this._longDateFormat[key];
    }

    var defaultInvalidDate = 'Invalid date';

    function invalidDate() {
        return this._invalidDate;
    }

    var defaultOrdinal = '%d',
        defaultDayOfMonthOrdinalParse = /\d{1,2}/;

    function ordinal(number) {
        return this._ordinal.replace('%d', number);
    }

    var defaultRelativeTime = {
        future: 'in %s',
        past: '%s ago',
        s: 'a few seconds',
        ss: '%d seconds',
        m: 'a minute',
        mm: '%d minutes',
        h: 'an hour',
        hh: '%d hours',
        d: 'a day',
        dd: '%d days',
        w: 'a week',
        ww: '%d weeks',
        M: 'a month',
        MM: '%d months',
        y: 'a year',
        yy: '%d years',
    };

    function relativeTime(number, withoutSuffix, string, isFuture) {
        var output = this._relativeTime[string];
        return isFunction(output)
            ? output(number, withoutSuffix, string, isFuture)
            : output.replace(/%d/i, number);
    }

    function pastFuture(diff, output) {
        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
        return isFunction(format) ? format(output) : format.replace(/%s/i, output);
    }

    var aliases = {};

    function addUnitAlias(unit, shorthand) {
        var lowerCase = unit.toLowerCase();
        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
    }

    function normalizeUnits(units) {
        return typeof units === 'string'
            ? aliases[units] || aliases[units.toLowerCase()]
            : undefined;
    }

    function normalizeObjectUnits(inputObject) {
        var normalizedInput = {},
            normalizedProp,
            prop;

        for (prop in inputObject) {
            if (hasOwnProp(inputObject, prop)) {
                normalizedProp = normalizeUnits(prop);
                if (normalizedProp) {
                    normalizedInput[normalizedProp] = inputObject[prop];
                }
            }
        }

        return normalizedInput;
    }

    var priorities = {};

    function addUnitPriority(unit, priority) {
        priorities[unit] = priority;
    }

    function getPrioritizedUnits(unitsObj) {
        var units = [],
            u;
        for (u in unitsObj) {
            if (hasOwnProp(unitsObj, u)) {
                units.push({ unit: u, priority: priorities[u] });
            }
        }
        units.sort(function (a, b) {
            return a.priority - b.priority;
        });
        return units;
    }

    function isLeapYear(year) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
    }

    function absFloor(number) {
        if (number < 0) {
            // -0 -> 0
            return Math.ceil(number) || 0;
        } else {
            return Math.floor(number);
        }
    }

    function toInt(argumentForCoercion) {
        var coercedNumber = +argumentForCoercion,
            value = 0;

        if (coercedNumber !== 0 && isFinite(coercedNumber)) {
            value = absFloor(coercedNumber);
        }

        return value;
    }

    function makeGetSet(unit, keepTime) {
        return function (value) {
            if (value != null) {
                set$1(this, unit, value);
                hooks.updateOffset(this, keepTime);
                return this;
            } else {
                return get(this, unit);
            }
        };
    }

    function get(mom, unit) {
        return mom.isValid()
            ? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
            : NaN;
    }

    function set$1(mom, unit, value) {
        if (mom.isValid() && !isNaN(value)) {
            if (
                unit === 'FullYear' &&
                isLeapYear(mom.year()) &&
                mom.month() === 1 &&
                mom.date() === 29
            ) {
                value = toInt(value);
                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](
                    value,
                    mom.month(),
                    daysInMonth(value, mom.month())
                );
            } else {
                mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
            }
        }
    }

    // MOMENTS

    function stringGet(units) {
        units = normalizeUnits(units);
        if (isFunction(this[units])) {
            return this[units]();
        }
        return this;
    }

    function stringSet(units, value) {
        if (typeof units === 'object') {
            units = normalizeObjectUnits(units);
            var prioritized = getPrioritizedUnits(units),
                i;
            for (i = 0; i < prioritized.length; i++) {
                this[prioritized[i].unit](units[prioritized[i].unit]);
            }
        } else {
            units = normalizeUnits(units);
            if (isFunction(this[units])) {
                return this[units](value);
            }
        }
        return this;
    }

    var match1 = /\d/, //       0 - 9
        match2 = /\d\d/, //      00 - 99
        match3 = /\d{3}/, //     000 - 999
        match4 = /\d{4}/, //    0000 - 9999
        match6 = /[+-]?\d{6}/, // -999999 - 999999
        match1to2 = /\d\d?/, //       0 - 99
        match3to4 = /\d\d\d\d?/, //     999 - 9999
        match5to6 = /\d\d\d\d\d\d?/, //   99999 - 999999
        match1to3 = /\d{1,3}/, //       0 - 999
        match1to4 = /\d{1,4}/, //       0 - 9999
        match1to6 = /[+-]?\d{1,6}/, // -999999 - 999999
        matchUnsigned = /\d+/, //       0 - inf
        matchSigned = /[+-]?\d+/, //    -inf - inf
        matchOffset = /Z|[+-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
        matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi, // +00 -00 +00:00 -00:00 +0000 -0000 or Z
        matchTimestamp = /[+-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
        // any word (or two) characters or numbers including two/three word month in arabic.
        // includes scottish gaelic two word and hyphenated months
        matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i,
        regexes;

    regexes = {};

    function addRegexToken(token, regex, strictRegex) {
        regexes[token] = isFunction(regex)
            ? regex
            : function (isStrict, localeData) {
                  return isStrict && strictRegex ? strictRegex : regex;
              };
    }

    function getParseRegexForToken(token, config) {
        if (!hasOwnProp(regexes, token)) {
            return new RegExp(unescapeFormat(token));
        }

        return regexes[token](config._strict, config._locale);
    }

    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
    function unescapeFormat(s) {
        return regexEscape(
            s
                .replace('\\', '')
                .replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (
                    matched,
                    p1,
                    p2,
                    p3,
                    p4
                ) {
                    return p1 || p2 || p3 || p4;
                })
        );
    }

    function regexEscape(s) {
        return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    }

    var tokens = {};

    function addParseToken(token, callback) {
        var i,
            func = callback;
        if (typeof token === 'string') {
            token = [token];
        }
        if (isNumber(callback)) {
            func = function (input, array) {
                array[callback] = toInt(input);
            };
        }
        for (i = 0; i < token.length; i++) {
            tokens[token[i]] = func;
        }
    }

    function addWeekParseToken(token, callback) {
        addParseToken(token, function (input, array, config, token) {
            config._w = config._w || {};
            callback(input, config._w, config, token);
        });
    }

    function addTimeToArrayFromToken(token, input, config) {
        if (input != null && hasOwnProp(tokens, token)) {
            tokens[token](input, config._a, config, token);
        }
    }

    var YEAR = 0,
        MONTH = 1,
        DATE = 2,
        HOUR = 3,
        MINUTE = 4,
        SECOND = 5,
        MILLISECOND = 6,
        WEEK = 7,
        WEEKDAY = 8;

    function mod(n, x) {
        return ((n % x) + x) % x;
    }

    var indexOf;

    if (Array.prototype.indexOf) {
        indexOf = Array.prototype.indexOf;
    } else {
        indexOf = function (o) {
            // I know
            var i;
            for (i = 0; i < this.length; ++i) {
                if (this[i] === o) {
                    return i;
                }
            }
            return -1;
        };
    }

    function daysInMonth(year, month) {
        if (isNaN(year) || isNaN(month)) {
            return NaN;
        }
        var modMonth = mod(month, 12);
        year += (month - modMonth) / 12;
        return modMonth === 1
            ? isLeapYear(year)
                ? 29
                : 28
            : 31 - ((modMonth % 7) % 2);
    }

    // FORMATTING

    addFormatToken('M', ['MM', 2], 'Mo', function () {
        return this.month() + 1;
    });

    addFormatToken('MMM', 0, 0, function (format) {
        return this.localeData().monthsShort(this, format);
    });

    addFormatToken('MMMM', 0, 0, function (format) {
        return this.localeData().months(this, format);
    });

    // ALIASES

    addUnitAlias('month', 'M');

    // PRIORITY

    addUnitPriority('month', 8);

    // PARSING

    addRegexToken('M', match1to2);
    addRegexToken('MM', match1to2, match2);
    addRegexToken('MMM', function (isStrict, locale) {
        return locale.monthsShortRegex(isStrict);
    });
    addRegexToken('MMMM', function (isStrict, locale) {
        return locale.monthsRegex(isStrict);
    });

    addParseToken(['M', 'MM'], function (input, array) {
        array[MONTH] = toInt(input) - 1;
    });

    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
        var month = config._locale.monthsParse(input, token, config._strict);
        // if we didn't find a month name, mark the date as invalid.
        if (month != null) {
            array[MONTH] = month;
        } else {
            getParsingFlags(config).invalidMonth = input;
        }
    });

    // LOCALES

    var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split(
            '_'
        ),
        defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split(
            '_'
        ),
        MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/,
        defaultMonthsShortRegex = matchWord,
        defaultMonthsRegex = matchWord;

    function localeMonths(m, format) {
        if (!m) {
            return isArray(this._months)
                ? this._months
                : this._months['standalone'];
        }
        return isArray(this._months)
            ? this._months[m.month()]
            : this._months[
                  (this._months.isFormat || MONTHS_IN_FORMAT).test(format)
                      ? 'format'
                      : 'standalone'
              ][m.month()];
    }

    function localeMonthsShort(m, format) {
        if (!m) {
            return isArray(this._monthsShort)
                ? this._monthsShort
                : this._monthsShort['standalone'];
        }
        return isArray(this._monthsShort)
            ? this._monthsShort[m.month()]
            : this._monthsShort[
                  MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'
              ][m.month()];
    }

    function handleStrictParse(monthName, format, strict) {
        var i,
            ii,
            mom,
            llc = monthName.toLocaleLowerCase();
        if (!this._monthsParse) {
            // this is not used
            this._monthsParse = [];
            this._longMonthsParse = [];
            this._shortMonthsParse = [];
            for (i = 0; i < 12; ++i) {
                mom = createUTC([2000, i]);
                this._shortMonthsParse[i] = this.monthsShort(
                    mom,
                    ''
                ).toLocaleLowerCase();
                this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
            }
        }

        if (strict) {
            if (format === 'MMM') {
                ii = indexOf.call(this._shortMonthsParse, llc);
                return ii !== -1 ? ii : null;
            } else {
                ii = indexOf.call(this._longMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
        } else {
            if (format === 'MMM') {
                ii = indexOf.call(this._shortMonthsParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._longMonthsParse, llc);
                return ii !== -1 ? ii : null;
            } else {
                ii = indexOf.call(this._longMonthsParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortMonthsParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
    }

    function localeMonthsParse(monthName, format, strict) {
        var i, mom, regex;

        if (this._monthsParseExact) {
            return handleStrictParse.call(this, monthName, format, strict);
        }

        if (!this._monthsParse) {
            this._monthsParse = [];
            this._longMonthsParse = [];
            this._shortMonthsParse = [];
        }

        // TODO: add sorting
        // Sorting makes sure if one month (or abbr) is a prefix of another
        // see sorting in computeMonthsParse
        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = createUTC([2000, i]);
            if (strict && !this._longMonthsParse[i]) {
                this._longMonthsParse[i] = new RegExp(
                    '^' + this.months(mom, '').replace('.', '') + '$',
                    'i'
                );
                this._shortMonthsParse[i] = new RegExp(
                    '^' + this.monthsShort(mom, '').replace('.', '') + '$',
                    'i'
                );
            }
            if (!strict && !this._monthsParse[i]) {
                regex =
                    '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
            }
            // test the regex
            if (
                strict &&
                format === 'MMMM' &&
                this._longMonthsParse[i].test(monthName)
            ) {
                return i;
            } else if (
                strict &&
                format === 'MMM' &&
                this._shortMonthsParse[i].test(monthName)
            ) {
                return i;
            } else if (!strict && this._monthsParse[i].test(monthName)) {
                return i;
            }
        }
    }

    // MOMENTS

    function setMonth(mom, value) {
        var dayOfMonth;

        if (!mom.isValid()) {
            // No op
            return mom;
        }

        if (typeof value === 'string') {
            if (/^\d+$/.test(value)) {
                value = toInt(value);
            } else {
                value = mom.localeData().monthsParse(value);
                // TODO: Another silent failure?
                if (!isNumber(value)) {
                    return mom;
                }
            }
        }

        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
        return mom;
    }

    function getSetMonth(value) {
        if (value != null) {
            setMonth(this, value);
            hooks.updateOffset(this, true);
            return this;
        } else {
            return get(this, 'Month');
        }
    }

    function getDaysInMonth() {
        return daysInMonth(this.year(), this.month());
    }

    function monthsShortRegex(isStrict) {
        if (this._monthsParseExact) {
            if (!hasOwnProp(this, '_monthsRegex')) {
                computeMonthsParse.call(this);
            }
            if (isStrict) {
                return this._monthsShortStrictRegex;
            } else {
                return this._monthsShortRegex;
            }
        } else {
            if (!hasOwnProp(this, '_monthsShortRegex')) {
                this._monthsShortRegex = defaultMonthsShortRegex;
            }
            return this._monthsShortStrictRegex && isStrict
                ? this._monthsShortStrictRegex
                : this._monthsShortRegex;
        }
    }

    function monthsRegex(isStrict) {
        if (this._monthsParseExact) {
            if (!hasOwnProp(this, '_monthsRegex')) {
                computeMonthsParse.call(this);
            }
            if (isStrict) {
                return this._monthsStrictRegex;
            } else {
                return this._monthsRegex;
            }
        } else {
            if (!hasOwnProp(this, '_monthsRegex')) {
                this._monthsRegex = defaultMonthsRegex;
            }
            return this._monthsStrictRegex && isStrict
                ? this._monthsStrictRegex
                : this._monthsRegex;
        }
    }

    function computeMonthsParse() {
        function cmpLenRev(a, b) {
            return b.length - a.length;
        }

        var shortPieces = [],
            longPieces = [],
            mixedPieces = [],
            i,
            mom;
        for (i = 0; i < 12; i++) {
            // make the regex if we don't have it already
            mom = createUTC([2000, i]);
            shortPieces.push(this.monthsShort(mom, ''));
            longPieces.push(this.months(mom, ''));
            mixedPieces.push(this.months(mom, ''));
            mixedPieces.push(this.monthsShort(mom, ''));
        }
        // Sorting makes sure if one month (or abbr) is a prefix of another it
        // will match the longer piece.
        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);
        for (i = 0; i < 12; i++) {
            shortPieces[i] = regexEscape(shortPieces[i]);
            longPieces[i] = regexEscape(longPieces[i]);
        }
        for (i = 0; i < 24; i++) {
            mixedPieces[i] = regexEscape(mixedPieces[i]);
        }

        this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._monthsShortRegex = this._monthsRegex;
        this._monthsStrictRegex = new RegExp(
            '^(' + longPieces.join('|') + ')',
            'i'
        );
        this._monthsShortStrictRegex = new RegExp(
            '^(' + shortPieces.join('|') + ')',
            'i'
        );
    }

    // FORMATTING

    addFormatToken('Y', 0, 0, function () {
        var y = this.year();
        return y <= 9999 ? zeroFill(y, 4) : '+' + y;
    });

    addFormatToken(0, ['YY', 2], 0, function () {
        return this.year() % 100;
    });

    addFormatToken(0, ['YYYY', 4], 0, 'year');
    addFormatToken(0, ['YYYYY', 5], 0, 'year');
    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');

    // ALIASES

    addUnitAlias('year', 'y');

    // PRIORITIES

    addUnitPriority('year', 1);

    // PARSING

    addRegexToken('Y', matchSigned);
    addRegexToken('YY', match1to2, match2);
    addRegexToken('YYYY', match1to4, match4);
    addRegexToken('YYYYY', match1to6, match6);
    addRegexToken('YYYYYY', match1to6, match6);

    addParseToken(['YYYYY', 'YYYYYY'], YEAR);
    addParseToken('YYYY', function (input, array) {
        array[YEAR] =
            input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);
    });
    addParseToken('YY', function (input, array) {
        array[YEAR] = hooks.parseTwoDigitYear(input);
    });
    addParseToken('Y', function (input, array) {
        array[YEAR] = parseInt(input, 10);
    });

    // HELPERS

    function daysInYear(year) {
        return isLeapYear(year) ? 366 : 365;
    }

    // HOOKS

    hooks.parseTwoDigitYear = function (input) {
        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
    };

    // MOMENTS

    var getSetYear = makeGetSet('FullYear', true);

    function getIsLeapYear() {
        return isLeapYear(this.year());
    }

    function createDate(y, m, d, h, M, s, ms) {
        // can't just apply() to create a date:
        // https://stackoverflow.com/q/181348
        var date;
        // the date constructor remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            date = new Date(y + 400, m, d, h, M, s, ms);
            if (isFinite(date.getFullYear())) {
                date.setFullYear(y);
            }
        } else {
            date = new Date(y, m, d, h, M, s, ms);
        }

        return date;
    }

    function createUTCDate(y) {
        var date, args;
        // the Date.UTC function remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            args = Array.prototype.slice.call(arguments);
            // preserve leap years using a full 400 year cycle, then reset
            args[0] = y + 400;
            date = new Date(Date.UTC.apply(null, args));
            if (isFinite(date.getUTCFullYear())) {
                date.setUTCFullYear(y);
            }
        } else {
            date = new Date(Date.UTC.apply(null, arguments));
        }

        return date;
    }

    // start-of-first-week - start-of-year
    function firstWeekOffset(year, dow, doy) {
        var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
            fwd = 7 + dow - doy,
            // first-week day local weekday -- which local weekday is fwd
            fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;

        return -fwdlw + fwd - 1;
    }

    // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
    function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
        var localWeekday = (7 + weekday - dow) % 7,
            weekOffset = firstWeekOffset(year, dow, doy),
            dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
            resYear,
            resDayOfYear;

        if (dayOfYear <= 0) {
            resYear = year - 1;
            resDayOfYear = daysInYear(resYear) + dayOfYear;
        } else if (dayOfYear > daysInYear(year)) {
            resYear = year + 1;
            resDayOfYear = dayOfYear - daysInYear(year);
        } else {
            resYear = year;
            resDayOfYear = dayOfYear;
        }

        return {
            year: resYear,
            dayOfYear: resDayOfYear,
        };
    }

    function weekOfYear(mom, dow, doy) {
        var weekOffset = firstWeekOffset(mom.year(), dow, doy),
            week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
            resWeek,
            resYear;

        if (week < 1) {
            resYear = mom.year() - 1;
            resWeek = week + weeksInYear(resYear, dow, doy);
        } else if (week > weeksInYear(mom.year(), dow, doy)) {
            resWeek = week - weeksInYear(mom.year(), dow, doy);
            resYear = mom.year() + 1;
        } else {
            resYear = mom.year();
            resWeek = week;
        }

        return {
            week: resWeek,
            year: resYear,
        };
    }

    function weeksInYear(year, dow, doy) {
        var weekOffset = firstWeekOffset(year, dow, doy),
            weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
        return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
    }

    // FORMATTING

    addFormatToken('w', ['ww', 2], 'wo', 'week');
    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');

    // ALIASES

    addUnitAlias('week', 'w');
    addUnitAlias('isoWeek', 'W');

    // PRIORITIES

    addUnitPriority('week', 5);
    addUnitPriority('isoWeek', 5);

    // PARSING

    addRegexToken('w', match1to2);
    addRegexToken('ww', match1to2, match2);
    addRegexToken('W', match1to2);
    addRegexToken('WW', match1to2, match2);

    addWeekParseToken(['w', 'ww', 'W', 'WW'], function (
        input,
        week,
        config,
        token
    ) {
        week[token.substr(0, 1)] = toInt(input);
    });

    // HELPERS

    // LOCALES

    function localeWeek(mom) {
        return weekOfYear(mom, this._week.dow, this._week.doy).week;
    }

    var defaultLocaleWeek = {
        dow: 0, // Sunday is the first day of the week.
        doy: 6, // The week that contains Jan 6th is the first week of the year.
    };

    function localeFirstDayOfWeek() {
        return this._week.dow;
    }

    function localeFirstDayOfYear() {
        return this._week.doy;
    }

    // MOMENTS

    function getSetWeek(input) {
        var week = this.localeData().week(this);
        return input == null ? week : this.add((input - week) * 7, 'd');
    }

    function getSetISOWeek(input) {
        var week = weekOfYear(this, 1, 4).week;
        return input == null ? week : this.add((input - week) * 7, 'd');
    }

    // FORMATTING

    addFormatToken('d', 0, 'do', 'day');

    addFormatToken('dd', 0, 0, function (format) {
        return this.localeData().weekdaysMin(this, format);
    });

    addFormatToken('ddd', 0, 0, function (format) {
        return this.localeData().weekdaysShort(this, format);
    });

    addFormatToken('dddd', 0, 0, function (format) {
        return this.localeData().weekdays(this, format);
    });

    addFormatToken('e', 0, 0, 'weekday');
    addFormatToken('E', 0, 0, 'isoWeekday');

    // ALIASES

    addUnitAlias('day', 'd');
    addUnitAlias('weekday', 'e');
    addUnitAlias('isoWeekday', 'E');

    // PRIORITY
    addUnitPriority('day', 11);
    addUnitPriority('weekday', 11);
    addUnitPriority('isoWeekday', 11);

    // PARSING

    addRegexToken('d', match1to2);
    addRegexToken('e', match1to2);
    addRegexToken('E', match1to2);
    addRegexToken('dd', function (isStrict, locale) {
        return locale.weekdaysMinRegex(isStrict);
    });
    addRegexToken('ddd', function (isStrict, locale) {
        return locale.weekdaysShortRegex(isStrict);
    });
    addRegexToken('dddd', function (isStrict, locale) {
        return locale.weekdaysRegex(isStrict);
    });

    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
        var weekday = config._locale.weekdaysParse(input, token, config._strict);
        // if we didn't get a weekday name, mark the date as invalid
        if (weekday != null) {
            week.d = weekday;
        } else {
            getParsingFlags(config).invalidWeekday = input;
        }
    });

    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
        week[token] = toInt(input);
    });

    // HELPERS

    function parseWeekday(input, locale) {
        if (typeof input !== 'string') {
            return input;
        }

        if (!isNaN(input)) {
            return parseInt(input, 10);
        }

        input = locale.weekdaysParse(input);
        if (typeof input === 'number') {
            return input;
        }

        return null;
    }

    function parseIsoWeekday(input, locale) {
        if (typeof input === 'string') {
            return locale.weekdaysParse(input) % 7 || 7;
        }
        return isNaN(input) ? null : input;
    }

    // LOCALES
    function shiftWeekdays(ws, n) {
        return ws.slice(n, 7).concat(ws.slice(0, n));
    }

    var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split(
            '_'
        ),
        defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),
        defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
        defaultWeekdaysRegex = matchWord,
        defaultWeekdaysShortRegex = matchWord,
        defaultWeekdaysMinRegex = matchWord;

    function localeWeekdays(m, format) {
        var weekdays = isArray(this._weekdays)
            ? this._weekdays
            : this._weekdays[
                  m && m !== true && this._weekdays.isFormat.test(format)
                      ? 'format'
                      : 'standalone'
              ];
        return m === true
            ? shiftWeekdays(weekdays, this._week.dow)
            : m
            ? weekdays[m.day()]
            : weekdays;
    }

    function localeWeekdaysShort(m) {
        return m === true
            ? shiftWeekdays(this._weekdaysShort, this._week.dow)
            : m
            ? this._weekdaysShort[m.day()]
            : this._weekdaysShort;
    }

    function localeWeekdaysMin(m) {
        return m === true
            ? shiftWeekdays(this._weekdaysMin, this._week.dow)
            : m
            ? this._weekdaysMin[m.day()]
            : this._weekdaysMin;
    }

    function handleStrictParse$1(weekdayName, format, strict) {
        var i,
            ii,
            mom,
            llc = weekdayName.toLocaleLowerCase();
        if (!this._weekdaysParse) {
            this._weekdaysParse = [];
            this._shortWeekdaysParse = [];
            this._minWeekdaysParse = [];

            for (i = 0; i < 7; ++i) {
                mom = createUTC([2000, 1]).day(i);
                this._minWeekdaysParse[i] = this.weekdaysMin(
                    mom,
                    ''
                ).toLocaleLowerCase();
                this._shortWeekdaysParse[i] = this.weekdaysShort(
                    mom,
                    ''
                ).toLocaleLowerCase();
                this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
            }
        }

        if (strict) {
            if (format === 'dddd') {
                ii = indexOf.call(this._weekdaysParse, llc);
                return ii !== -1 ? ii : null;
            } else if (format === 'ddd') {
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            } else {
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
        } else {
            if (format === 'dddd') {
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            } else if (format === 'ddd') {
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._minWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            } else {
                ii = indexOf.call(this._minWeekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._weekdaysParse, llc);
                if (ii !== -1) {
                    return ii;
                }
                ii = indexOf.call(this._shortWeekdaysParse, llc);
                return ii !== -1 ? ii : null;
            }
        }
    }

    function localeWeekdaysParse(weekdayName, format, strict) {
        var i, mom, regex;

        if (this._weekdaysParseExact) {
            return handleStrictParse$1.call(this, weekdayName, format, strict);
        }

        if (!this._weekdaysParse) {
            this._weekdaysParse = [];
            this._minWeekdaysParse = [];
            this._shortWeekdaysParse = [];
            this._fullWeekdaysParse = [];
        }

        for (i = 0; i < 7; i++) {
            // make the regex if we don't have it already

            mom = createUTC([2000, 1]).day(i);
            if (strict && !this._fullWeekdaysParse[i]) {
                this._fullWeekdaysParse[i] = new RegExp(
                    '^' + this.weekdays(mom, '').replace('.', '\\.?') + '$',
                    'i'
                );
                this._shortWeekdaysParse[i] = new RegExp(
                    '^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$',
                    'i'
                );
                this._minWeekdaysParse[i] = new RegExp(
                    '^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$',
                    'i'
                );
            }
            if (!this._weekdaysParse[i]) {
                regex =
                    '^' +
                    this.weekdays(mom, '') +
                    '|^' +
                    this.weekdaysShort(mom, '') +
                    '|^' +
                    this.weekdaysMin(mom, '');
                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
            }
            // test the regex
            if (
                strict &&
                format === 'dddd' &&
                this._fullWeekdaysParse[i].test(weekdayName)
            ) {
                return i;
            } else if (
                strict &&
                format === 'ddd' &&
                this._shortWeekdaysParse[i].test(weekdayName)
            ) {
                return i;
            } else if (
                strict &&
                format === 'dd' &&
                this._minWeekdaysParse[i].test(weekdayName)
            ) {
                return i;
            } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
                return i;
            }
        }
    }

    // MOMENTS

    function getSetDayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
        if (input != null) {
            input = parseWeekday(input, this.localeData());
            return this.add(input - day, 'd');
        } else {
            return day;
        }
    }

    function getSetLocaleDayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
        return input == null ? weekday : this.add(input - weekday, 'd');
    }

    function getSetISODayOfWeek(input) {
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }

        // behaves the same as moment#day except
        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
        // as a setter, sunday should belong to the previous week.

        if (input != null) {
            var weekday = parseIsoWeekday(input, this.localeData());
            return this.day(this.day() % 7 ? weekday : weekday - 7);
        } else {
            return this.day() || 7;
        }
    }

    function weekdaysRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysStrictRegex;
            } else {
                return this._weekdaysRegex;
            }
        } else {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                this._weekdaysRegex = defaultWeekdaysRegex;
            }
            return this._weekdaysStrictRegex && isStrict
                ? this._weekdaysStrictRegex
                : this._weekdaysRegex;
        }
    }

    function weekdaysShortRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysShortStrictRegex;
            } else {
                return this._weekdaysShortRegex;
            }
        } else {
            if (!hasOwnProp(this, '_weekdaysShortRegex')) {
                this._weekdaysShortRegex = defaultWeekdaysShortRegex;
            }
            return this._weekdaysShortStrictRegex && isStrict
                ? this._weekdaysShortStrictRegex
                : this._weekdaysShortRegex;
        }
    }

    function weekdaysMinRegex(isStrict) {
        if (this._weekdaysParseExact) {
            if (!hasOwnProp(this, '_weekdaysRegex')) {
                computeWeekdaysParse.call(this);
            }
            if (isStrict) {
                return this._weekdaysMinStrictRegex;
            } else {
                return this._weekdaysMinRegex;
            }
        } else {
            if (!hasOwnProp(this, '_weekdaysMinRegex')) {
                this._weekdaysMinRegex = defaultWeekdaysMinRegex;
            }
            return this._weekdaysMinStrictRegex && isStrict
                ? this._weekdaysMinStrictRegex
                : this._weekdaysMinRegex;
        }
    }

    function computeWeekdaysParse() {
        function cmpLenRev(a, b) {
            return b.length - a.length;
        }

        var minPieces = [],
            shortPieces = [],
            longPieces = [],
            mixedPieces = [],
            i,
            mom,
            minp,
            shortp,
            longp;
        for (i = 0; i < 7; i++) {
            // make the regex if we don't have it already
            mom = createUTC([2000, 1]).day(i);
            minp = regexEscape(this.weekdaysMin(mom, ''));
            shortp = regexEscape(this.weekdaysShort(mom, ''));
            longp = regexEscape(this.weekdays(mom, ''));
            minPieces.push(minp);
            shortPieces.push(shortp);
            longPieces.push(longp);
            mixedPieces.push(minp);
            mixedPieces.push(shortp);
            mixedPieces.push(longp);
        }
        // Sorting makes sure if one weekday (or abbr) is a prefix of another it
        // will match the longer piece.
        minPieces.sort(cmpLenRev);
        shortPieces.sort(cmpLenRev);
        longPieces.sort(cmpLenRev);
        mixedPieces.sort(cmpLenRev);

        this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._weekdaysShortRegex = this._weekdaysRegex;
        this._weekdaysMinRegex = this._weekdaysRegex;

        this._weekdaysStrictRegex = new RegExp(
            '^(' + longPieces.join('|') + ')',
            'i'
        );
        this._weekdaysShortStrictRegex = new RegExp(
            '^(' + shortPieces.join('|') + ')',
            'i'
        );
        this._weekdaysMinStrictRegex = new RegExp(
            '^(' + minPieces.join('|') + ')',
            'i'
        );
    }

    // FORMATTING

    function hFormat() {
        return this.hours() % 12 || 12;
    }

    function kFormat() {
        return this.hours() || 24;
    }

    addFormatToken('H', ['HH', 2], 0, 'hour');
    addFormatToken('h', ['hh', 2], 0, hFormat);
    addFormatToken('k', ['kk', 2], 0, kFormat);

    addFormatToken('hmm', 0, 0, function () {
        return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
    });

    addFormatToken('hmmss', 0, 0, function () {
        return (
            '' +
            hFormat.apply(this) +
            zeroFill(this.minutes(), 2) +
            zeroFill(this.seconds(), 2)
        );
    });

    addFormatToken('Hmm', 0, 0, function () {
        return '' + this.hours() + zeroFill(this.minutes(), 2);
    });

    addFormatToken('Hmmss', 0, 0, function () {
        return (
            '' +
            this.hours() +
            zeroFill(this.minutes(), 2) +
            zeroFill(this.seconds(), 2)
        );
    });

    function meridiem(token, lowercase) {
        addFormatToken(token, 0, 0, function () {
            return this.localeData().meridiem(
                this.hours(),
                this.minutes(),
                lowercase
            );
        });
    }

    meridiem('a', true);
    meridiem('A', false);

    // ALIASES

    addUnitAlias('hour', 'h');

    // PRIORITY
    addUnitPriority('hour', 13);

    // PARSING

    function matchMeridiem(isStrict, locale) {
        return locale._meridiemParse;
    }

    addRegexToken('a', matchMeridiem);
    addRegexToken('A', matchMeridiem);
    addRegexToken('H', match1to2);
    addRegexToken('h', match1to2);
    addRegexToken('k', match1to2);
    addRegexToken('HH', match1to2, match2);
    addRegexToken('hh', match1to2, match2);
    addRegexToken('kk', match1to2, match2);

    addRegexToken('hmm', match3to4);
    addRegexToken('hmmss', match5to6);
    addRegexToken('Hmm', match3to4);
    addRegexToken('Hmmss', match5to6);

    addParseToken(['H', 'HH'], HOUR);
    addParseToken(['k', 'kk'], function (input, array, config) {
        var kInput = toInt(input);
        array[HOUR] = kInput === 24 ? 0 : kInput;
    });
    addParseToken(['a', 'A'], function (input, array, config) {
        config._isPm = config._locale.isPM(input);
        config._meridiem = input;
    });
    addParseToken(['h', 'hh'], function (input, array, config) {
        array[HOUR] = toInt(input);
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('hmm', function (input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('hmmss', function (input, array, config) {
        var pos1 = input.length - 4,
            pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
        getParsingFlags(config).bigHour = true;
    });
    addParseToken('Hmm', function (input, array, config) {
        var pos = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos));
        array[MINUTE] = toInt(input.substr(pos));
    });
    addParseToken('Hmmss', function (input, array, config) {
        var pos1 = input.length - 4,
            pos2 = input.length - 2;
        array[HOUR] = toInt(input.substr(0, pos1));
        array[MINUTE] = toInt(input.substr(pos1, 2));
        array[SECOND] = toInt(input.substr(pos2));
    });

    // LOCALES

    function localeIsPM(input) {
        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
        // Using charAt should be more compatible.
        return (input + '').toLowerCase().charAt(0) === 'p';
    }

    var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i,
        // Setting the hour should keep the time, because the user explicitly
        // specified which hour they want. So trying to maintain the same hour (in
        // a new timezone) makes sense. Adding/subtracting hours does not follow
        // this rule.
        getSetHour = makeGetSet('Hours', true);

    function localeMeridiem(hours, minutes, isLower) {
        if (hours > 11) {
            return isLower ? 'pm' : 'PM';
        } else {
            return isLower ? 'am' : 'AM';
        }
    }

    var baseConfig = {
        calendar: defaultCalendar,
        longDateFormat: defaultLongDateFormat,
        invalidDate: defaultInvalidDate,
        ordinal: defaultOrdinal,
        dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,
        relativeTime: defaultRelativeTime,

        months: defaultLocaleMonths,
        monthsShort: defaultLocaleMonthsShort,

        week: defaultLocaleWeek,

        weekdays: defaultLocaleWeekdays,
        weekdaysMin: defaultLocaleWeekdaysMin,
        weekdaysShort: defaultLocaleWeekdaysShort,

        meridiemParse: defaultLocaleMeridiemParse,
    };

    // internal storage for locale config files
    var locales = {},
        localeFamilies = {},
        globalLocale;

    function commonPrefix(arr1, arr2) {
        var i,
            minl = Math.min(arr1.length, arr2.length);
        for (i = 0; i < minl; i += 1) {
            if (arr1[i] !== arr2[i]) {
                return i;
            }
        }
        return minl;
    }

    function normalizeLocale(key) {
        return key ? key.toLowerCase().replace('_', '-') : key;
    }

    // pick the locale from the array
    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
    function chooseLocale(names) {
        var i = 0,
            j,
            next,
            locale,
            split;

        while (i < names.length) {
            split = normalizeLocale(names[i]).split('-');
            j = split.length;
            next = normalizeLocale(names[i + 1]);
            next = next ? next.split('-') : null;
            while (j > 0) {
                locale = loadLocale(split.slice(0, j).join('-'));
                if (locale) {
                    return locale;
                }
                if (
                    next &&
                    next.length >= j &&
                    commonPrefix(split, next) >= j - 1
                ) {
                    //the next array item is better than a shallower substring of this one
                    break;
                }
                j--;
            }
            i++;
        }
        return globalLocale;
    }

    function loadLocale(name) {
        var oldLocale = null,
            aliasedRequire;
        // TODO: Find a better way to register and load all the locales in Node
        if (
            locales[name] === undefined &&
            typeof module !== 'undefined' &&
            module &&
            module.exports
        ) {
            try {
                oldLocale = globalLocale._abbr;
                aliasedRequire = require;
                aliasedRequire('./locale/' + name);
                getSetGlobalLocale(oldLocale);
            } catch (e) {
                // mark as not found to avoid repeating expensive file require call causing high CPU
                // when trying to find en-US, en_US, en-us for every format call
                locales[name] = null; // null means not found
            }
        }
        return locales[name];
    }

    // This function will load locale and then set the global locale.  If
    // no arguments are passed in, it will simply return the current global
    // locale key.
    function getSetGlobalLocale(key, values) {
        var data;
        if (key) {
            if (isUndefined(values)) {
                data = getLocale(key);
            } else {
                data = defineLocale(key, values);
            }

            if (data) {
                // moment.duration._locale = moment._locale = data;
                globalLocale = data;
            } else {
                if (typeof console !== 'undefined' && console.warn) {
                    //warn user if arguments are passed but the locale could not be set
                    console.warn(
                        'Locale ' + key + ' not found. Did you forget to load it?'
                    );
                }
            }
        }

        return globalLocale._abbr;
    }

    function defineLocale(name, config) {
        if (config !== null) {
            var locale,
                parentConfig = baseConfig;
            config.abbr = name;
            if (locales[name] != null) {
                deprecateSimple(
                    'defineLocaleOverride',
                    'use moment.updateLocale(localeName, config) to change ' +
                        'an existing locale. moment.defineLocale(localeName, ' +
                        'config) should only be used for creating a new locale ' +
                        'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.'
                );
                parentConfig = locales[name]._config;
            } else if (config.parentLocale != null) {
                if (locales[config.parentLocale] != null) {
                    parentConfig = locales[config.parentLocale]._config;
                } else {
                    locale = loadLocale(config.parentLocale);
                    if (locale != null) {
                        parentConfig = locale._config;
                    } else {
                        if (!localeFamilies[config.parentLocale]) {
                            localeFamilies[config.parentLocale] = [];
                        }
                        localeFamilies[config.parentLocale].push({
                            name: name,
                            config: config,
                        });
                        return null;
                    }
                }
            }
            locales[name] = new Locale(mergeConfigs(parentConfig, config));

            if (localeFamilies[name]) {
                localeFamilies[name].forEach(function (x) {
                    defineLocale(x.name, x.config);
                });
            }

            // backwards compat for now: also set the locale
            // make sure we set the locale AFTER all child locales have been
            // created, so we won't end up with the child locale set.
            getSetGlobalLocale(name);

            return locales[name];
        } else {
            // useful for testing
            delete locales[name];
            return null;
        }
    }

    function updateLocale(name, config) {
        if (config != null) {
            var locale,
                tmpLocale,
                parentConfig = baseConfig;

            if (locales[name] != null && locales[name].parentLocale != null) {
                // Update existing child locale in-place to avoid memory-leaks
                locales[name].set(mergeConfigs(locales[name]._config, config));
            } else {
                // MERGE
                tmpLocale = loadLocale(name);
                if (tmpLocale != null) {
                    parentConfig = tmpLocale._config;
                }
                config = mergeConfigs(parentConfig, config);
                if (tmpLocale == null) {
                    // updateLocale is called for creating a new locale
                    // Set abbr so it will have a name (getters return
                    // undefined otherwise).
                    config.abbr = name;
                }
                locale = new Locale(config);
                locale.parentLocale = locales[name];
                locales[name] = locale;
            }

            // backwards compat for now: also set the locale
            getSetGlobalLocale(name);
        } else {
            // pass null for config to unupdate, useful for tests
            if (locales[name] != null) {
                if (locales[name].parentLocale != null) {
                    locales[name] = locales[name].parentLocale;
                    if (name === getSetGlobalLocale()) {
                        getSetGlobalLocale(name);
                    }
                } else if (locales[name] != null) {
                    delete locales[name];
                }
            }
        }
        return locales[name];
    }

    // returns locale data
    function getLocale(key) {
        var locale;

        if (key && key._locale && key._locale._abbr) {
            key = key._locale._abbr;
        }

        if (!key) {
            return globalLocale;
        }

        if (!isArray(key)) {
            //short-circuit everything else
            locale = loadLocale(key);
            if (locale) {
                return locale;
            }
            key = [key];
        }

        return chooseLocale(key);
    }

    function listLocales() {
        return keys(locales);
    }

    function checkOverflow(m) {
        var overflow,
            a = m._a;

        if (a && getParsingFlags(m).overflow === -2) {
            overflow =
                a[MONTH] < 0 || a[MONTH] > 11
                    ? MONTH
                    : a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH])
                    ? DATE
                    : a[HOUR] < 0 ||
                      a[HOUR] > 24 ||
                      (a[HOUR] === 24 &&
                          (a[MINUTE] !== 0 ||
                              a[SECOND] !== 0 ||
                              a[MILLISECOND] !== 0))
                    ? HOUR
                    : a[MINUTE] < 0 || a[MINUTE] > 59
                    ? MINUTE
                    : a[SECOND] < 0 || a[SECOND] > 59
                    ? SECOND
                    : a[MILLISECOND] < 0 || a[MILLISECOND] > 999
                    ? MILLISECOND
                    : -1;

            if (
                getParsingFlags(m)._overflowDayOfYear &&
                (overflow < YEAR || overflow > DATE)
            ) {
                overflow = DATE;
            }
            if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
                overflow = WEEK;
            }
            if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
                overflow = WEEKDAY;
            }

            getParsingFlags(m).overflow = overflow;
        }

        return m;
    }

    // iso 8601 regex
    // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
    var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
        basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
        tzRegex = /Z|[+-]\d\d(?::?\d\d)?/,
        isoDates = [
            ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
            ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
            ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
            ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
            ['YYYY-DDD', /\d{4}-\d{3}/],
            ['YYYY-MM', /\d{4}-\d\d/, false],
            ['YYYYYYMMDD', /[+-]\d{10}/],
            ['YYYYMMDD', /\d{8}/],
            ['GGGG[W]WWE', /\d{4}W\d{3}/],
            ['GGGG[W]WW', /\d{4}W\d{2}/, false],
            ['YYYYDDD', /\d{7}/],
            ['YYYYMM', /\d{6}/, false],
            ['YYYY', /\d{4}/, false],
        ],
        // iso time formats and regexes
        isoTimes = [
            ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
            ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
            ['HH:mm:ss', /\d\d:\d\d:\d\d/],
            ['HH:mm', /\d\d:\d\d/],
            ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
            ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
            ['HHmmss', /\d\d\d\d\d\d/],
            ['HHmm', /\d\d\d\d/],
            ['HH', /\d\d/],
        ],
        aspNetJsonRegex = /^\/?Date\((-?\d+)/i,
        // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
        rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,
        obsOffsets = {
            UT: 0,
            GMT: 0,
            EDT: -4 * 60,
            EST: -5 * 60,
            CDT: -5 * 60,
            CST: -6 * 60,
            MDT: -6 * 60,
            MST: -7 * 60,
            PDT: -7 * 60,
            PST: -8 * 60,
        };

    // date from iso format
    function configFromISO(config) {
        var i,
            l,
            string = config._i,
            match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
            allowTime,
            dateFormat,
            timeFormat,
            tzFormat;

        if (match) {
            getParsingFlags(config).iso = true;

            for (i = 0, l = isoDates.length; i < l; i++) {
                if (isoDates[i][1].exec(match[1])) {
                    dateFormat = isoDates[i][0];
                    allowTime = isoDates[i][2] !== false;
                    break;
                }
            }
            if (dateFormat == null) {
                config._isValid = false;
                return;
            }
            if (match[3]) {
                for (i = 0, l = isoTimes.length; i < l; i++) {
                    if (isoTimes[i][1].exec(match[3])) {
                        // match[2] should be 'T' or space
                        timeFormat = (match[2] || ' ') + isoTimes[i][0];
                        break;
                    }
                }
                if (timeFormat == null) {
                    config._isValid = false;
                    return;
                }
            }
            if (!allowTime && timeFormat != null) {
                config._isValid = false;
                return;
            }
            if (match[4]) {
                if (tzRegex.exec(match[4])) {
                    tzFormat = 'Z';
                } else {
                    config._isValid = false;
                    return;
                }
            }
            config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
            configFromStringAndFormat(config);
        } else {
            config._isValid = false;
        }
    }

    function extractFromRFC2822Strings(
        yearStr,
        monthStr,
        dayStr,
        hourStr,
        minuteStr,
        secondStr
    ) {
        var result = [
            untruncateYear(yearStr),
            defaultLocaleMonthsShort.indexOf(monthStr),
            parseInt(dayStr, 10),
            parseInt(hourStr, 10),
            parseInt(minuteStr, 10),
        ];

        if (secondStr) {
            result.push(parseInt(secondStr, 10));
        }

        return result;
    }

    function untruncateYear(yearStr) {
        var year = parseInt(yearStr, 10);
        if (year <= 49) {
            return 2000 + year;
        } else if (year <= 999) {
            return 1900 + year;
        }
        return year;
    }

    function preprocessRFC2822(s) {
        // Remove comments and folding whitespace and replace multiple-spaces with a single space
        return s
            .replace(/\([^)]*\)|[\n\t]/g, ' ')
            .replace(/(\s\s+)/g, ' ')
            .replace(/^\s\s*/, '')
            .replace(/\s\s*$/, '');
    }

    function checkWeekday(weekdayStr, parsedInput, config) {
        if (weekdayStr) {
            // TODO: Replace the vanilla JS Date object with an independent day-of-week check.
            var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
                weekdayActual = new Date(
                    parsedInput[0],
                    parsedInput[1],
                    parsedInput[2]
                ).getDay();
            if (weekdayProvided !== weekdayActual) {
                getParsingFlags(config).weekdayMismatch = true;
                config._isValid = false;
                return false;
            }
        }
        return true;
    }

    function calculateOffset(obsOffset, militaryOffset, numOffset) {
        if (obsOffset) {
            return obsOffsets[obsOffset];
        } else if (militaryOffset) {
            // the only allowed military tz is Z
            return 0;
        } else {
            var hm = parseInt(numOffset, 10),
                m = hm % 100,
                h = (hm - m) / 100;
            return h * 60 + m;
        }
    }

    // date and time from ref 2822 format
    function configFromRFC2822(config) {
        var match = rfc2822.exec(preprocessRFC2822(config._i)),
            parsedArray;
        if (match) {
            parsedArray = extractFromRFC2822Strings(
                match[4],
                match[3],
                match[2],
                match[5],
                match[6],
                match[7]
            );
            if (!checkWeekday(match[1], parsedArray, config)) {
                return;
            }

            config._a = parsedArray;
            config._tzm = calculateOffset(match[8], match[9], match[10]);

            config._d = createUTCDate.apply(null, config._a);
            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);

            getParsingFlags(config).rfc2822 = true;
        } else {
            config._isValid = false;
        }
    }

    // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict
    function configFromString(config) {
        var matched = aspNetJsonRegex.exec(config._i);
        if (matched !== null) {
            config._d = new Date(+matched[1]);
            return;
        }

        configFromISO(config);
        if (config._isValid === false) {
            delete config._isValid;
        } else {
            return;
        }

        configFromRFC2822(config);
        if (config._isValid === false) {
            delete config._isValid;
        } else {
            return;
        }

        if (config._strict) {
            config._isValid = false;
        } else {
            // Final attempt, use Input Fallback
            hooks.createFromInputFallback(config);
        }
    }

    hooks.createFromInputFallback = deprecate(
        'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
            'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
            'discouraged and will be removed in an upcoming major release. Please refer to ' +
            'http://momentjs.com/guides/#/warnings/js-date/ for more info.',
        function (config) {
            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
        }
    );

    // Pick the first defined of two or three arguments.
    function defaults(a, b, c) {
        if (a != null) {
            return a;
        }
        if (b != null) {
            return b;
        }
        return c;
    }

    function currentDateArray(config) {
        // hooks is actually the exported moment object
        var nowValue = new Date(hooks.now());
        if (config._useUTC) {
            return [
                nowValue.getUTCFullYear(),
                nowValue.getUTCMonth(),
                nowValue.getUTCDate(),
            ];
        }
        return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
    }

    // convert an array to a date.
    // the array should mirror the parameters below
    // note: all values past the year are optional and will default to the lowest possible value.
    // [year, month, day , hour, minute, second, millisecond]
    function configFromArray(config) {
        var i,
            date,
            input = [],
            currentDate,
            expectedWeekday,
            yearToUse;

        if (config._d) {
            return;
        }

        currentDate = currentDateArray(config);

        //compute day of the year from weeks and weekdays
        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
            dayOfYearFromWeekInfo(config);
        }

        //if the day of the year is set, figure out what it is
        if (config._dayOfYear != null) {
            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);

            if (
                config._dayOfYear > daysInYear(yearToUse) ||
                config._dayOfYear === 0
            ) {
                getParsingFlags(config)._overflowDayOfYear = true;
            }

            date = createUTCDate(yearToUse, 0, config._dayOfYear);
            config._a[MONTH] = date.getUTCMonth();
            config._a[DATE] = date.getUTCDate();
        }

        // Default to current date.
        // * if no year, month, day of month are given, default to today
        // * if day of month is given, default month and year
        // * if month is given, default only year
        // * if year is given, don't default anything
        for (i = 0; i < 3 && config._a[i] == null; ++i) {
            config._a[i] = input[i] = currentDate[i];
        }

        // Zero out whatever was not defaulted, including time
        for (; i < 7; i++) {
            config._a[i] = input[i] =
                config._a[i] == null ? (i === 2 ? 1 : 0) : config._a[i];
        }

        // Check for 24:00:00.000
        if (
            config._a[HOUR] === 24 &&
            config._a[MINUTE] === 0 &&
            config._a[SECOND] === 0 &&
            config._a[MILLISECOND] === 0
        ) {
            config._nextDay = true;
            config._a[HOUR] = 0;
        }

        config._d = (config._useUTC ? createUTCDate : createDate).apply(
            null,
            input
        );
        expectedWeekday = config._useUTC
            ? config._d.getUTCDay()
            : config._d.getDay();

        // Apply timezone offset from input. The actual utcOffset can be changed
        // with parseZone.
        if (config._tzm != null) {
            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
        }

        if (config._nextDay) {
            config._a[HOUR] = 24;
        }

        // check for mismatching day of week
        if (
            config._w &&
            typeof config._w.d !== 'undefined' &&
            config._w.d !== expectedWeekday
        ) {
            getParsingFlags(config).weekdayMismatch = true;
        }
    }

    function dayOfYearFromWeekInfo(config) {
        var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow, curWeek;

        w = config._w;
        if (w.GG != null || w.W != null || w.E != null) {
            dow = 1;
            doy = 4;

            // TODO: We need to take the current isoWeekYear, but that depends on
            // how we interpret now (local, utc, fixed offset). So create
            // a now version of current config (take local/utc/offset flags, and
            // create now).
            weekYear = defaults(
                w.GG,
                config._a[YEAR],
                weekOfYear(createLocal(), 1, 4).year
            );
            week = defaults(w.W, 1);
            weekday = defaults(w.E, 1);
            if (weekday < 1 || weekday > 7) {
                weekdayOverflow = true;
            }
        } else {
            dow = config._locale._week.dow;
            doy = config._locale._week.doy;

            curWeek = weekOfYear(createLocal(), dow, doy);

            weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);

            // Default to current week.
            week = defaults(w.w, curWeek.week);

            if (w.d != null) {
                // weekday -- low day numbers are considered next week
                weekday = w.d;
                if (weekday < 0 || weekday > 6) {
                    weekdayOverflow = true;
                }
            } else if (w.e != null) {
                // local weekday -- counting starts from beginning of week
                weekday = w.e + dow;
                if (w.e < 0 || w.e > 6) {
                    weekdayOverflow = true;
                }
            } else {
                // default to beginning of week
                weekday = dow;
            }
        }
        if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
            getParsingFlags(config)._overflowWeeks = true;
        } else if (weekdayOverflow != null) {
            getParsingFlags(config)._overflowWeekday = true;
        } else {
            temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
            config._a[YEAR] = temp.year;
            config._dayOfYear = temp.dayOfYear;
        }
    }

    // constant that refers to the ISO standard
    hooks.ISO_8601 = function () {};

    // constant that refers to the RFC 2822 form
    hooks.RFC_2822 = function () {};

    // date from string and format string
    function configFromStringAndFormat(config) {
        // TODO: Move this to another part of the creation flow to prevent circular deps
        if (config._f === hooks.ISO_8601) {
            configFromISO(config);
            return;
        }
        if (config._f === hooks.RFC_2822) {
            configFromRFC2822(config);
            return;
        }
        config._a = [];
        getParsingFlags(config).empty = true;

        // This array is used to make a Date, either with `new Date` or `Date.UTC`
        var string = '' + config._i,
            i,
            parsedInput,
            tokens,
            token,
            skipped,
            stringLength = string.length,
            totalParsedInputLength = 0,
            era;

        tokens =
            expandFormat(config._f, config._locale).match(formattingTokens) || [];

        for (i = 0; i < tokens.length; i++) {
            token = tokens[i];
            parsedInput = (string.match(getParseRegexForToken(token, config)) ||
                [])[0];
            if (parsedInput) {
                skipped = string.substr(0, string.indexOf(parsedInput));
                if (skipped.length > 0) {
                    getParsingFlags(config).unusedInput.push(skipped);
                }
                string = string.slice(
                    string.indexOf(parsedInput) + parsedInput.length
                );
                totalParsedInputLength += parsedInput.length;
            }
            // don't parse if it's not a known token
            if (formatTokenFunctions[token]) {
                if (parsedInput) {
                    getParsingFlags(config).empty = false;
                } else {
                    getParsingFlags(config).unusedTokens.push(token);
                }
                addTimeToArrayFromToken(token, parsedInput, config);
            } else if (config._strict && !parsedInput) {
                getParsingFlags(config).unusedTokens.push(token);
            }
        }

        // add remaining unparsed input length to the string
        getParsingFlags(config).charsLeftOver =
            stringLength - totalParsedInputLength;
        if (string.length > 0) {
            getParsingFlags(config).unusedInput.push(string);
        }

        // clear _12h flag if hour is <= 12
        if (
            config._a[HOUR] <= 12 &&
            getParsingFlags(config).bigHour === true &&
            config._a[HOUR] > 0
        ) {
            getParsingFlags(config).bigHour = undefined;
        }

        getParsingFlags(config).parsedDateParts = config._a.slice(0);
        getParsingFlags(config).meridiem = config._meridiem;
        // handle meridiem
        config._a[HOUR] = meridiemFixWrap(
            config._locale,
            config._a[HOUR],
            config._meridiem
        );

        // handle era
        era = getParsingFlags(config).era;
        if (era !== null) {
            config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
        }

        configFromArray(config);
        checkOverflow(config);
    }

    function meridiemFixWrap(locale, hour, meridiem) {
        var isPm;

        if (meridiem == null) {
            // nothing to do
            return hour;
        }
        if (locale.meridiemHour != null) {
            return locale.meridiemHour(hour, meridiem);
        } else if (locale.isPM != null) {
            // Fallback
            isPm = locale.isPM(meridiem);
            if (isPm && hour < 12) {
                hour += 12;
            }
            if (!isPm && hour === 12) {
                hour = 0;
            }
            return hour;
        } else {
            // this is not supposed to happen
            return hour;
        }
    }

    // date from string and array of format strings
    function configFromStringAndArray(config) {
        var tempConfig,
            bestMoment,
            scoreToBeat,
            i,
            currentScore,
            validFormatFound,
            bestFormatIsValid = false;

        if (config._f.length === 0) {
            getParsingFlags(config).invalidFormat = true;
            config._d = new Date(NaN);
            return;
        }

        for (i = 0; i < config._f.length; i++) {
            currentScore = 0;
            validFormatFound = false;
            tempConfig = copyConfig({}, config);
            if (config._useUTC != null) {
                tempConfig._useUTC = config._useUTC;
            }
            tempConfig._f = config._f[i];
            configFromStringAndFormat(tempConfig);

            if (isValid(tempConfig)) {
                validFormatFound = true;
            }

            // if there is any input that was not parsed add a penalty for that format
            currentScore += getParsingFlags(tempConfig).charsLeftOver;

            //or tokens
            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;

            getParsingFlags(tempConfig).score = currentScore;

            if (!bestFormatIsValid) {
                if (
                    scoreToBeat == null ||
                    currentScore < scoreToBeat ||
                    validFormatFound
                ) {
                    scoreToBeat = currentScore;
                    bestMoment = tempConfig;
                    if (validFormatFound) {
                        bestFormatIsValid = true;
                    }
                }
            } else {
                if (currentScore < scoreToBeat) {
                    scoreToBeat = currentScore;
                    bestMoment = tempConfig;
                }
            }
        }

        extend(config, bestMoment || tempConfig);
    }

    function configFromObject(config) {
        if (config._d) {
            return;
        }

        var i = normalizeObjectUnits(config._i),
            dayOrDate = i.day === undefined ? i.date : i.day;
        config._a = map(
            [i.year, i.month, dayOrDate, i.hour, i.minute, i.second, i.millisecond],
            function (obj) {
                return obj && parseInt(obj, 10);
            }
        );

        configFromArray(config);
    }

    function createFromConfig(config) {
        var res = new Moment(checkOverflow(prepareConfig(config)));
        if (res._nextDay) {
            // Adding is smart enough around DST
            res.add(1, 'd');
            res._nextDay = undefined;
        }

        return res;
    }

    function prepareConfig(config) {
        var input = config._i,
            format = config._f;

        config._locale = config._locale || getLocale(config._l);

        if (input === null || (format === undefined && input === '')) {
            return createInvalid({ nullInput: true });
        }

        if (typeof input === 'string') {
            config._i = input = config._locale.preparse(input);
        }

        if (isMoment(input)) {
            return new Moment(checkOverflow(input));
        } else if (isDate(input)) {
            config._d = input;
        } else if (isArray(format)) {
            configFromStringAndArray(config);
        } else if (format) {
            configFromStringAndFormat(config);
        } else {
            configFromInput(config);
        }

        if (!isValid(config)) {
            config._d = null;
        }

        return config;
    }

    function configFromInput(config) {
        var input = config._i;
        if (isUndefined(input)) {
            config._d = new Date(hooks.now());
        } else if (isDate(input)) {
            config._d = new Date(input.valueOf());
        } else if (typeof input === 'string') {
            configFromString(config);
        } else if (isArray(input)) {
            config._a = map(input.slice(0), function (obj) {
                return parseInt(obj, 10);
            });
            configFromArray(config);
        } else if (isObject(input)) {
            configFromObject(config);
        } else if (isNumber(input)) {
            // from milliseconds
            config._d = new Date(input);
        } else {
            hooks.createFromInputFallback(config);
        }
    }

    function createLocalOrUTC(input, format, locale, strict, isUTC) {
        var c = {};

        if (format === true || format === false) {
            strict = format;
            format = undefined;
        }

        if (locale === true || locale === false) {
            strict = locale;
            locale = undefined;
        }

        if (
            (isObject(input) && isObjectEmpty(input)) ||
            (isArray(input) && input.length === 0)
        ) {
            input = undefined;
        }
        // object construction must be done this way.
        // https://github.com/moment/moment/issues/1423
        c._isAMomentObject = true;
        c._useUTC = c._isUTC = isUTC;
        c._l = locale;
        c._i = input;
        c._f = format;
        c._strict = strict;

        return createFromConfig(c);
    }

    function createLocal(input, format, locale, strict) {
        return createLocalOrUTC(input, format, locale, strict, false);
    }

    var prototypeMin = deprecate(
            'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',
            function () {
                var other = createLocal.apply(null, arguments);
                if (this.isValid() && other.isValid()) {
                    return other < this ? this : other;
                } else {
                    return createInvalid();
                }
            }
        ),
        prototypeMax = deprecate(
            'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',
            function () {
                var other = createLocal.apply(null, arguments);
                if (this.isValid() && other.isValid()) {
                    return other > this ? this : other;
                } else {
                    return createInvalid();
                }
            }
        );

    // Pick a moment m from moments so that m[fn](other) is true for all
    // other. This relies on the function fn to be transitive.
    //
    // moments should either be an array of moment objects or an array, whose
    // first element is an array of moment objects.
    function pickBy(fn, moments) {
        var res, i;
        if (moments.length === 1 && isArray(moments[0])) {
            moments = moments[0];
        }
        if (!moments.length) {
            return createLocal();
        }
        res = moments[0];
        for (i = 1; i < moments.length; ++i) {
            if (!moments[i].isValid() || moments[i][fn](res)) {
                res = moments[i];
            }
        }
        return res;
    }

    // TODO: Use [].sort instead?
    function min() {
        var args = [].slice.call(arguments, 0);

        return pickBy('isBefore', args);
    }

    function max() {
        var args = [].slice.call(arguments, 0);

        return pickBy('isAfter', args);
    }

    var now = function () {
        return Date.now ? Date.now() : +new Date();
    };

    var ordering = [
        'year',
        'quarter',
        'month',
        'week',
        'day',
        'hour',
        'minute',
        'second',
        'millisecond',
    ];

    function isDurationValid(m) {
        var key,
            unitHasDecimal = false,
            i;
        for (key in m) {
            if (
                hasOwnProp(m, key) &&
                !(
                    indexOf.call(ordering, key) !== -1 &&
                    (m[key] == null || !isNaN(m[key]))
                )
            ) {
                return false;
            }
        }

        for (i = 0; i < ordering.length; ++i) {
            if (m[ordering[i]]) {
                if (unitHasDecimal) {
                    return false; // only allow non-integers for smallest unit
                }
                if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {
                    unitHasDecimal = true;
                }
            }
        }

        return true;
    }

    function isValid$1() {
        return this._isValid;
    }

    function createInvalid$1() {
        return createDuration(NaN);
    }

    function Duration(duration) {
        var normalizedInput = normalizeObjectUnits(duration),
            years = normalizedInput.year || 0,
            quarters = normalizedInput.quarter || 0,
            months = normalizedInput.month || 0,
            weeks = normalizedInput.week || normalizedInput.isoWeek || 0,
            days = normalizedInput.day || 0,
            hours = normalizedInput.hour || 0,
            minutes = normalizedInput.minute || 0,
            seconds = normalizedInput.second || 0,
            milliseconds = normalizedInput.millisecond || 0;

        this._isValid = isDurationValid(normalizedInput);

        // representation for dateAddRemove
        this._milliseconds =
            +milliseconds +
            seconds * 1e3 + // 1000
            minutes * 6e4 + // 1000 * 60
            hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
        // Because of dateAddRemove treats 24 hours as different from a
        // day when working around DST, we need to store them separately
        this._days = +days + weeks * 7;
        // It is impossible to translate months into days without knowing
        // which months you are are talking about, so we have to store
        // it separately.
        this._months = +months + quarters * 3 + years * 12;

        this._data = {};

        this._locale = getLocale();

        this._bubble();
    }

    function isDuration(obj) {
        return obj instanceof Duration;
    }

    function absRound(number) {
        if (number < 0) {
            return Math.round(-1 * number) * -1;
        } else {
            return Math.round(number);
        }
    }

    // compare two arrays, return the number of differences
    function compareArrays(array1, array2, dontConvert) {
        var len = Math.min(array1.length, array2.length),
            lengthDiff = Math.abs(array1.length - array2.length),
            diffs = 0,
            i;
        for (i = 0; i < len; i++) {
            if (
                (dontConvert && array1[i] !== array2[i]) ||
                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))
            ) {
                diffs++;
            }
        }
        return diffs + lengthDiff;
    }

    // FORMATTING

    function offset(token, separator) {
        addFormatToken(token, 0, 0, function () {
            var offset = this.utcOffset(),
                sign = '+';
            if (offset < 0) {
                offset = -offset;
                sign = '-';
            }
            return (
                sign +
                zeroFill(~~(offset / 60), 2) +
                separator +
                zeroFill(~~offset % 60, 2)
            );
        });
    }

    offset('Z', ':');
    offset('ZZ', '');

    // PARSING

    addRegexToken('Z', matchShortOffset);
    addRegexToken('ZZ', matchShortOffset);
    addParseToken(['Z', 'ZZ'], function (input, array, config) {
        config._useUTC = true;
        config._tzm = offsetFromString(matchShortOffset, input);
    });

    // HELPERS

    // timezone chunker
    // '+10:00' > ['10',  '00']
    // '-1530'  > ['-15', '30']
    var chunkOffset = /([\+\-]|\d\d)/gi;

    function offsetFromString(matcher, string) {
        var matches = (string || '').match(matcher),
            chunk,
            parts,
            minutes;

        if (matches === null) {
            return null;
        }

        chunk = matches[matches.length - 1] || [];
        parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
        minutes = +(parts[1] * 60) + toInt(parts[2]);

        return minutes === 0 ? 0 : parts[0] === '+' ? minutes : -minutes;
    }

    // Return a moment from input, that is local/utc/zone equivalent to model.
    function cloneWithOffset(input, model) {
        var res, diff;
        if (model._isUTC) {
            res = model.clone();
            diff =
                (isMoment(input) || isDate(input)
                    ? input.valueOf()
                    : createLocal(input).valueOf()) - res.valueOf();
            // Use low-level api, because this fn is low-level api.
            res._d.setTime(res._d.valueOf() + diff);
            hooks.updateOffset(res, false);
            return res;
        } else {
            return createLocal(input).local();
        }
    }

    function getDateOffset(m) {
        // On Firefox.24 Date#getTimezoneOffset returns a floating point.
        // https://github.com/moment/moment/pull/1871
        return -Math.round(m._d.getTimezoneOffset());
    }

    // HOOKS

    // This function will be called whenever a moment is mutated.
    // It is intended to keep the offset in sync with the timezone.
    hooks.updateOffset = function () {};

    // MOMENTS

    // keepLocalTime = true means only change the timezone, without
    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
    // +0200, so we adjust the time as needed, to be valid.
    //
    // Keeping the time actually adds/subtracts (one hour)
    // from the actual represented time. That is why we call updateOffset
    // a second time. In case it wants us to change the offset again
    // _changeInProgress == true case, then we have to adjust, because
    // there is no such time in the given timezone.
    function getSetOffset(input, keepLocalTime, keepMinutes) {
        var offset = this._offset || 0,
            localAdjust;
        if (!this.isValid()) {
            return input != null ? this : NaN;
        }
        if (input != null) {
            if (typeof input === 'string') {
                input = offsetFromString(matchShortOffset, input);
                if (input === null) {
                    return this;
                }
            } else if (Math.abs(input) < 16 && !keepMinutes) {
                input = input * 60;
            }
            if (!this._isUTC && keepLocalTime) {
                localAdjust = getDateOffset(this);
            }
            this._offset = input;
            this._isUTC = true;
            if (localAdjust != null) {
                this.add(localAdjust, 'm');
            }
            if (offset !== input) {
                if (!keepLocalTime || this._changeInProgress) {
                    addSubtract(
                        this,
                        createDuration(input - offset, 'm'),
                        1,
                        false
                    );
                } else if (!this._changeInProgress) {
                    this._changeInProgress = true;
                    hooks.updateOffset(this, true);
                    this._changeInProgress = null;
                }
            }
            return this;
        } else {
            return this._isUTC ? offset : getDateOffset(this);
        }
    }

    function getSetZone(input, keepLocalTime) {
        if (input != null) {
            if (typeof input !== 'string') {
                input = -input;
            }

            this.utcOffset(input, keepLocalTime);

            return this;
        } else {
            return -this.utcOffset();
        }
    }

    function setOffsetToUTC(keepLocalTime) {
        return this.utcOffset(0, keepLocalTime);
    }

    function setOffsetToLocal(keepLocalTime) {
        if (this._isUTC) {
            this.utcOffset(0, keepLocalTime);
            this._isUTC = false;

            if (keepLocalTime) {
                this.subtract(getDateOffset(this), 'm');
            }
        }
        return this;
    }

    function setOffsetToParsedOffset() {
        if (this._tzm != null) {
            this.utcOffset(this._tzm, false, true);
        } else if (typeof this._i === 'string') {
            var tZone = offsetFromString(matchOffset, this._i);
            if (tZone != null) {
                this.utcOffset(tZone);
            } else {
                this.utcOffset(0, true);
            }
        }
        return this;
    }

    function hasAlignedHourOffset(input) {
        if (!this.isValid()) {
            return false;
        }
        input = input ? createLocal(input).utcOffset() : 0;

        return (this.utcOffset() - input) % 60 === 0;
    }

    function isDaylightSavingTime() {
        return (
            this.utcOffset() > this.clone().month(0).utcOffset() ||
            this.utcOffset() > this.clone().month(5).utcOffset()
        );
    }

    function isDaylightSavingTimeShifted() {
        if (!isUndefined(this._isDSTShifted)) {
            return this._isDSTShifted;
        }

        var c = {},
            other;

        copyConfig(c, this);
        c = prepareConfig(c);

        if (c._a) {
            other = c._isUTC ? createUTC(c._a) : createLocal(c._a);
            this._isDSTShifted =
                this.isValid() && compareArrays(c._a, other.toArray()) > 0;
        } else {
            this._isDSTShifted = false;
        }

        return this._isDSTShifted;
    }

    function isLocal() {
        return this.isValid() ? !this._isUTC : false;
    }

    function isUtcOffset() {
        return this.isValid() ? this._isUTC : false;
    }

    function isUtc() {
        return this.isValid() ? this._isUTC && this._offset === 0 : false;
    }

    // ASP.NET json date format regex
    var aspNetRegex = /^(-|\+)?(?:(\d*)[. ])?(\d+):(\d+)(?::(\d+)(\.\d*)?)?$/,
        // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
        // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
        // and further modified to allow for strings containing both week and day
        isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;

    function createDuration(input, key) {
        var duration = input,
            // matching against regexp is expensive, do it on demand
            match = null,
            sign,
            ret,
            diffRes;

        if (isDuration(input)) {
            duration = {
                ms: input._milliseconds,
                d: input._days,
                M: input._months,
            };
        } else if (isNumber(input) || !isNaN(+input)) {
            duration = {};
            if (key) {
                duration[key] = +input;
            } else {
                duration.milliseconds = +input;
            }
        } else if ((match = aspNetRegex.exec(input))) {
            sign = match[1] === '-' ? -1 : 1;
            duration = {
                y: 0,
                d: toInt(match[DATE]) * sign,
                h: toInt(match[HOUR]) * sign,
                m: toInt(match[MINUTE]) * sign,
                s: toInt(match[SECOND]) * sign,
                ms: toInt(absRound(match[MILLISECOND] * 1000)) * sign, // the millisecond decimal point is included in the match
            };
        } else if ((match = isoRegex.exec(input))) {
            sign = match[1] === '-' ? -1 : 1;
            duration = {
                y: parseIso(match[2], sign),
                M: parseIso(match[3], sign),
                w: parseIso(match[4], sign),
                d: parseIso(match[5], sign),
                h: parseIso(match[6], sign),
                m: parseIso(match[7], sign),
                s: parseIso(match[8], sign),
            };
        } else if (duration == null) {
            // checks for null or undefined
            duration = {};
        } else if (
            typeof duration === 'object' &&
            ('from' in duration || 'to' in duration)
        ) {
            diffRes = momentsDifference(
                createLocal(duration.from),
                createLocal(duration.to)
            );

            duration = {};
            duration.ms = diffRes.milliseconds;
            duration.M = diffRes.months;
        }

        ret = new Duration(duration);

        if (isDuration(input) && hasOwnProp(input, '_locale')) {
            ret._locale = input._locale;
        }

        if (isDuration(input) && hasOwnProp(input, '_isValid')) {
            ret._isValid = input._isValid;
        }

        return ret;
    }

    createDuration.fn = Duration.prototype;
    createDuration.invalid = createInvalid$1;

    function parseIso(inp, sign) {
        // We'd normally use ~~inp for this, but unfortunately it also
        // converts floats to ints.
        // inp may be undefined, so careful calling replace on it.
        var res = inp && parseFloat(inp.replace(',', '.'));
        // apply sign while we're at it
        return (isNaN(res) ? 0 : res) * sign;
    }

    function positiveMomentsDifference(base, other) {
        var res = {};

        res.months =
            other.month() - base.month() + (other.year() - base.year()) * 12;
        if (base.clone().add(res.months, 'M').isAfter(other)) {
            --res.months;
        }

        res.milliseconds = +other - +base.clone().add(res.months, 'M');

        return res;
    }

    function momentsDifference(base, other) {
        var res;
        if (!(base.isValid() && other.isValid())) {
            return { milliseconds: 0, months: 0 };
        }

        other = cloneWithOffset(other, base);
        if (base.isBefore(other)) {
            res = positiveMomentsDifference(base, other);
        } else {
            res = positiveMomentsDifference(other, base);
            res.milliseconds = -res.milliseconds;
            res.months = -res.months;
        }

        return res;
    }

    // TODO: remove 'name' arg after deprecation is removed
    function createAdder(direction, name) {
        return function (val, period) {
            var dur, tmp;
            //invert the arguments, but complain about it
            if (period !== null && !isNaN(+period)) {
                deprecateSimple(
                    name,
                    'moment().' +
                        name +
                        '(period, number) is deprecated. Please use moment().' +
                        name +
                        '(number, period). ' +
                        'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.'
                );
                tmp = val;
                val = period;
                period = tmp;
            }

            dur = createDuration(val, period);
            addSubtract(this, dur, direction);
            return this;
        };
    }

    function addSubtract(mom, duration, isAdding, updateOffset) {
        var milliseconds = duration._milliseconds,
            days = absRound(duration._days),
            months = absRound(duration._months);

        if (!mom.isValid()) {
            // No op
            return;
        }

        updateOffset = updateOffset == null ? true : updateOffset;

        if (months) {
            setMonth(mom, get(mom, 'Month') + months * isAdding);
        }
        if (days) {
            set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);
        }
        if (milliseconds) {
            mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
        }
        if (updateOffset) {
            hooks.updateOffset(mom, days || months);
        }
    }

    var add = createAdder(1, 'add'),
        subtract = createAdder(-1, 'subtract');

    function isString(input) {
        return typeof input === 'string' || input instanceof String;
    }

    // type MomentInput = Moment | Date | string | number | (number | string)[] | MomentInputObject | void; // null | undefined
    function isMomentInput(input) {
        return (
            isMoment(input) ||
            isDate(input) ||
            isString(input) ||
            isNumber(input) ||
            isNumberOrStringArray(input) ||
            isMomentInputObject(input) ||
            input === null ||
            input === undefined
        );
    }

    function isMomentInputObject(input) {
        var objectTest = isObject(input) && !isObjectEmpty(input),
            propertyTest = false,
            properties = [
                'years',
                'year',
                'y',
                'months',
                'month',
                'M',
                'days',
                'day',
                'd',
                'dates',
                'date',
                'D',
                'hours',
                'hour',
                'h',
                'minutes',
                'minute',
                'm',
                'seconds',
                'second',
                's',
                'milliseconds',
                'millisecond',
                'ms',
            ],
            i,
            property;

        for (i = 0; i < properties.length; i += 1) {
            property = properties[i];
            propertyTest = propertyTest || hasOwnProp(input, property);
        }

        return objectTest && propertyTest;
    }

    function isNumberOrStringArray(input) {
        var arrayTest = isArray(input),
            dataTypeTest = false;
        if (arrayTest) {
            dataTypeTest =
                input.filter(function (item) {
                    return !isNumber(item) && isString(input);
                }).length === 0;
        }
        return arrayTest && dataTypeTest;
    }

    function isCalendarSpec(input) {
        var objectTest = isObject(input) && !isObjectEmpty(input),
            propertyTest = false,
            properties = [
                'sameDay',
                'nextDay',
                'lastDay',
                'nextWeek',
                'lastWeek',
                'sameElse',
            ],
            i,
            property;

        for (i = 0; i < properties.length; i += 1) {
            property = properties[i];
            propertyTest = propertyTest || hasOwnProp(input, property);
        }

        return objectTest && propertyTest;
    }

    function getCalendarFormat(myMoment, now) {
        var diff = myMoment.diff(now, 'days', true);
        return diff < -6
            ? 'sameElse'
            : diff < -1
            ? 'lastWeek'
            : diff < 0
            ? 'lastDay'
            : diff < 1
            ? 'sameDay'
            : diff < 2
            ? 'nextDay'
            : diff < 7
            ? 'nextWeek'
            : 'sameElse';
    }

    function calendar$1(time, formats) {
        // Support for single parameter, formats only overload to the calendar function
        if (arguments.length === 1) {
            if (isMomentInput(arguments[0])) {
                time = arguments[0];
                formats = undefined;
            } else if (isCalendarSpec(arguments[0])) {
                formats = arguments[0];
                time = undefined;
            }
        }
        // We want to compare the start of today, vs this.
        // Getting start-of-today depends on whether we're local/utc/offset or not.
        var now = time || createLocal(),
            sod = cloneWithOffset(now, this).startOf('day'),
            format = hooks.calendarFormat(this, sod) || 'sameElse',
            output =
                formats &&
                (isFunction(formats[format])
                    ? formats[format].call(this, now)
                    : formats[format]);

        return this.format(
            output || this.localeData().calendar(format, this, createLocal(now))
        );
    }

    function clone() {
        return new Moment(this);
    }

    function isAfter(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input);
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(units) || 'millisecond';
        if (units === 'millisecond') {
            return this.valueOf() > localInput.valueOf();
        } else {
            return localInput.valueOf() < this.clone().startOf(units).valueOf();
        }
    }

    function isBefore(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input);
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(units) || 'millisecond';
        if (units === 'millisecond') {
            return this.valueOf() < localInput.valueOf();
        } else {
            return this.clone().endOf(units).valueOf() < localInput.valueOf();
        }
    }

    function isBetween(from, to, units, inclusivity) {
        var localFrom = isMoment(from) ? from : createLocal(from),
            localTo = isMoment(to) ? to : createLocal(to);
        if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {
            return false;
        }
        inclusivity = inclusivity || '()';
        return (
            (inclusivity[0] === '('
                ? this.isAfter(localFrom, units)
                : !this.isBefore(localFrom, units)) &&
            (inclusivity[1] === ')'
                ? this.isBefore(localTo, units)
                : !this.isAfter(localTo, units))
        );
    }

    function isSame(input, units) {
        var localInput = isMoment(input) ? input : createLocal(input),
            inputMs;
        if (!(this.isValid() && localInput.isValid())) {
            return false;
        }
        units = normalizeUnits(units) || 'millisecond';
        if (units === 'millisecond') {
            return this.valueOf() === localInput.valueOf();
        } else {
            inputMs = localInput.valueOf();
            return (
                this.clone().startOf(units).valueOf() <= inputMs &&
                inputMs <= this.clone().endOf(units).valueOf()
            );
        }
    }

    function isSameOrAfter(input, units) {
        return this.isSame(input, units) || this.isAfter(input, units);
    }

    function isSameOrBefore(input, units) {
        return this.isSame(input, units) || this.isBefore(input, units);
    }

    function diff(input, units, asFloat) {
        var that, zoneDelta, output;

        if (!this.isValid()) {
            return NaN;
        }

        that = cloneWithOffset(input, this);

        if (!that.isValid()) {
            return NaN;
        }

        zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;

        units = normalizeUnits(units);

        switch (units) {
            case 'year':
                output = monthDiff(this, that) / 12;
                break;
            case 'month':
                output = monthDiff(this, that);
                break;
            case 'quarter':
                output = monthDiff(this, that) / 3;
                break;
            case 'second':
                output = (this - that) / 1e3;
                break; // 1000
            case 'minute':
                output = (this - that) / 6e4;
                break; // 1000 * 60
            case 'hour':
                output = (this - that) / 36e5;
                break; // 1000 * 60 * 60
            case 'day':
                output = (this - that - zoneDelta) / 864e5;
                break; // 1000 * 60 * 60 * 24, negate dst
            case 'week':
                output = (this - that - zoneDelta) / 6048e5;
                break; // 1000 * 60 * 60 * 24 * 7, negate dst
            default:
                output = this - that;
        }

        return asFloat ? output : absFloor(output);
    }

    function monthDiff(a, b) {
        if (a.date() < b.date()) {
            // end-of-month calculations work correct when the start month has more
            // days than the end month.
            return -monthDiff(b, a);
        }
        // difference in months
        var wholeMonthDiff = (b.year() - a.year()) * 12 + (b.month() - a.month()),
            // b is in (anchor - 1 month, anchor + 1 month)
            anchor = a.clone().add(wholeMonthDiff, 'months'),
            anchor2,
            adjust;

        if (b - anchor < 0) {
            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
            // linear across the month
            adjust = (b - anchor) / (anchor - anchor2);
        } else {
            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
            // linear across the month
            adjust = (b - anchor) / (anchor2 - anchor);
        }

        //check for negative zero, return zero if negative zero
        return -(wholeMonthDiff + adjust) || 0;
    }

    hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
    hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';

    function toString() {
        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
    }

    function toISOString(keepOffset) {
        if (!this.isValid()) {
            return null;
        }
        var utc = keepOffset !== true,
            m = utc ? this.clone().utc() : this;
        if (m.year() < 0 || m.year() > 9999) {
            return formatMoment(
                m,
                utc
                    ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'
                    : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ'
            );
        }
        if (isFunction(Date.prototype.toISOString)) {
            // native implementation is ~50x faster, use it when we can
            if (utc) {
                return this.toDate().toISOString();
            } else {
                return new Date(this.valueOf() + this.utcOffset() * 60 * 1000)
                    .toISOString()
                    .replace('Z', formatMoment(m, 'Z'));
            }
        }
        return formatMoment(
            m,
            utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ'
        );
    }

    /**
     * Return a human readable representation of a moment that can
     * also be evaluated to get a new moment which is the same
     *
     * @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects
     */
    function inspect() {
        if (!this.isValid()) {
            return 'moment.invalid(/* ' + this._i + ' */)';
        }
        var func = 'moment',
            zone = '',
            prefix,
            year,
            datetime,
            suffix;
        if (!this.isLocal()) {
            func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';
            zone = 'Z';
        }
        prefix = '[' + func + '("]';
        year = 0 <= this.year() && this.year() <= 9999 ? 'YYYY' : 'YYYYYY';
        datetime = '-MM-DD[T]HH:mm:ss.SSS';
        suffix = zone + '[")]';

        return this.format(prefix + year + datetime + suffix);
    }

    function format(inputString) {
        if (!inputString) {
            inputString = this.isUtc()
                ? hooks.defaultFormatUtc
                : hooks.defaultFormat;
        }
        var output = formatMoment(this, inputString);
        return this.localeData().postformat(output);
    }

    function from(time, withoutSuffix) {
        if (
            this.isValid() &&
            ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
        ) {
            return createDuration({ to: this, from: time })
                .locale(this.locale())
                .humanize(!withoutSuffix);
        } else {
            return this.localeData().invalidDate();
        }
    }

    function fromNow(withoutSuffix) {
        return this.from(createLocal(), withoutSuffix);
    }

    function to(time, withoutSuffix) {
        if (
            this.isValid() &&
            ((isMoment(time) && time.isValid()) || createLocal(time).isValid())
        ) {
            return createDuration({ from: this, to: time })
                .locale(this.locale())
                .humanize(!withoutSuffix);
        } else {
            return this.localeData().invalidDate();
        }
    }

    function toNow(withoutSuffix) {
        return this.to(createLocal(), withoutSuffix);
    }

    // If passed a locale key, it will set the locale for this
    // instance.  Otherwise, it will return the locale configuration
    // variables for this instance.
    function locale(key) {
        var newLocaleData;

        if (key === undefined) {
            return this._locale._abbr;
        } else {
            newLocaleData = getLocale(key);
            if (newLocaleData != null) {
                this._locale = newLocaleData;
            }
            return this;
        }
    }

    var lang = deprecate(
        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
        function (key) {
            if (key === undefined) {
                return this.localeData();
            } else {
                return this.locale(key);
            }
        }
    );

    function localeData() {
        return this._locale;
    }

    var MS_PER_SECOND = 1000,
        MS_PER_MINUTE = 60 * MS_PER_SECOND,
        MS_PER_HOUR = 60 * MS_PER_MINUTE,
        MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;

    // actual modulo - handles negative numbers (for dates before 1970):
    function mod$1(dividend, divisor) {
        return ((dividend % divisor) + divisor) % divisor;
    }

    function localStartOfDate(y, m, d) {
        // the date constructor remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            return new Date(y + 400, m, d) - MS_PER_400_YEARS;
        } else {
            return new Date(y, m, d).valueOf();
        }
    }

    function utcStartOfDate(y, m, d) {
        // Date.UTC remaps years 0-99 to 1900-1999
        if (y < 100 && y >= 0) {
            // preserve leap years using a full 400 year cycle, then reset
            return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;
        } else {
            return Date.UTC(y, m, d);
        }
    }

    function startOf(units) {
        var time, startOfDate;
        units = normalizeUnits(units);
        if (units === undefined || units === 'millisecond' || !this.isValid()) {
            return this;
        }

        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

        switch (units) {
            case 'year':
                time = startOfDate(this.year(), 0, 1);
                break;
            case 'quarter':
                time = startOfDate(
                    this.year(),
                    this.month() - (this.month() % 3),
                    1
                );
                break;
            case 'month':
                time = startOfDate(this.year(), this.month(), 1);
                break;
            case 'week':
                time = startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - this.weekday()
                );
                break;
            case 'isoWeek':
                time = startOfDate(
                    this.year(),
                    this.month(),
                    this.date() - (this.isoWeekday() - 1)
                );
                break;
            case 'day':
            case 'date':
                time = startOfDate(this.year(), this.month(), this.date());
                break;
            case 'hour':
                time = this._d.valueOf();
                time -= mod$1(
                    time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                    MS_PER_HOUR
                );
                break;
            case 'minute':
                time = this._d.valueOf();
                time -= mod$1(time, MS_PER_MINUTE);
                break;
            case 'second':
                time = this._d.valueOf();
                time -= mod$1(time, MS_PER_SECOND);
                break;
        }

        this._d.setTime(time);
        hooks.updateOffset(this, true);
        return this;
    }

    function endOf(units) {
        var time, startOfDate;
        units = normalizeUnits(units);
        if (units === undefined || units === 'millisecond' || !this.isValid()) {
            return this;
        }

        startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;

        switch (units) {
            case 'year':
                time = startOfDate(this.year() + 1, 0, 1) - 1;
                break;
            case 'quarter':
                time =
                    startOfDate(
                        this.year(),
                        this.month() - (this.month() % 3) + 3,
                        1
                    ) - 1;
                break;
            case 'month':
                time = startOfDate(this.year(), this.month() + 1, 1) - 1;
                break;
            case 'week':
                time =
                    startOfDate(
                        this.year(),
                        this.month(),
                        this.date() - this.weekday() + 7
                    ) - 1;
                break;
            case 'isoWeek':
                time =
                    startOfDate(
                        this.year(),
                        this.month(),
                        this.date() - (this.isoWeekday() - 1) + 7
                    ) - 1;
                break;
            case 'day':
            case 'date':
                time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;
                break;
            case 'hour':
                time = this._d.valueOf();
                time +=
                    MS_PER_HOUR -
                    mod$1(
                        time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE),
                        MS_PER_HOUR
                    ) -
                    1;
                break;
            case 'minute':
                time = this._d.valueOf();
                time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;
                break;
            case 'second':
                time = this._d.valueOf();
                time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;
                break;
        }

        this._d.setTime(time);
        hooks.updateOffset(this, true);
        return this;
    }

    function valueOf() {
        return this._d.valueOf() - (this._offset || 0) * 60000;
    }

    function unix() {
        return Math.floor(this.valueOf() / 1000);
    }

    function toDate() {
        return new Date(this.valueOf());
    }

    function toArray() {
        var m = this;
        return [
            m.year(),
            m.month(),
            m.date(),
            m.hour(),
            m.minute(),
            m.second(),
            m.millisecond(),
        ];
    }

    function toObject() {
        var m = this;
        return {
            years: m.year(),
            months: m.month(),
            date: m.date(),
            hours: m.hours(),
            minutes: m.minutes(),
            seconds: m.seconds(),
            milliseconds: m.milliseconds(),
        };
    }

    function toJSON() {
        // new Date(NaN).toJSON() === null
        return this.isValid() ? this.toISOString() : null;
    }

    function isValid$2() {
        return isValid(this);
    }

    function parsingFlags() {
        return extend({}, getParsingFlags(this));
    }

    function invalidAt() {
        return getParsingFlags(this).overflow;
    }

    function creationData() {
        return {
            input: this._i,
            format: this._f,
            locale: this._locale,
            isUTC: this._isUTC,
            strict: this._strict,
        };
    }

    addFormatToken('N', 0, 0, 'eraAbbr');
    addFormatToken('NN', 0, 0, 'eraAbbr');
    addFormatToken('NNN', 0, 0, 'eraAbbr');
    addFormatToken('NNNN', 0, 0, 'eraName');
    addFormatToken('NNNNN', 0, 0, 'eraNarrow');

    addFormatToken('y', ['y', 1], 'yo', 'eraYear');
    addFormatToken('y', ['yy', 2], 0, 'eraYear');
    addFormatToken('y', ['yyy', 3], 0, 'eraYear');
    addFormatToken('y', ['yyyy', 4], 0, 'eraYear');

    addRegexToken('N', matchEraAbbr);
    addRegexToken('NN', matchEraAbbr);
    addRegexToken('NNN', matchEraAbbr);
    addRegexToken('NNNN', matchEraName);
    addRegexToken('NNNNN', matchEraNarrow);

    addParseToken(['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], function (
        input,
        array,
        config,
        token
    ) {
        var era = config._locale.erasParse(input, token, config._strict);
        if (era) {
            getParsingFlags(config).era = era;
        } else {
            getParsingFlags(config).invalidEra = input;
        }
    });

    addRegexToken('y', matchUnsigned);
    addRegexToken('yy', matchUnsigned);
    addRegexToken('yyy', matchUnsigned);
    addRegexToken('yyyy', matchUnsigned);
    addRegexToken('yo', matchEraYearOrdinal);

    addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
    addParseToken(['yo'], function (input, array, config, token) {
        var match;
        if (config._locale._eraYearOrdinalRegex) {
            match = input.match(config._locale._eraYearOrdinalRegex);
        }

        if (config._locale.eraYearOrdinalParse) {
            array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
        } else {
            array[YEAR] = parseInt(input, 10);
        }
    });

    function localeEras(m, format) {
        var i,
            l,
            date,
            eras = this._eras || getLocale('en')._eras;
        for (i = 0, l = eras.length; i < l; ++i) {
            switch (typeof eras[i].since) {
                case 'string':
                    // truncate time
                    date = hooks(eras[i].since).startOf('day');
                    eras[i].since = date.valueOf();
                    break;
            }

            switch (typeof eras[i].until) {
                case 'undefined':
                    eras[i].until = +Infinity;
                    break;
                case 'string':
                    // truncate time
                    date = hooks(eras[i].until).startOf('day').valueOf();
                    eras[i].until = date.valueOf();
                    break;
            }
        }
        return eras;
    }

    function localeErasParse(eraName, format, strict) {
        var i,
            l,
            eras = this.eras(),
            name,
            abbr,
            narrow;
        eraName = eraName.toUpperCase();

        for (i = 0, l = eras.length; i < l; ++i) {
            name = eras[i].name.toUpperCase();
            abbr = eras[i].abbr.toUpperCase();
            narrow = eras[i].narrow.toUpperCase();

            if (strict) {
                switch (format) {
                    case 'N':
                    case 'NN':
                    case 'NNN':
                        if (abbr === eraName) {
                            return eras[i];
                        }
                        break;

                    case 'NNNN':
                        if (name === eraName) {
                            return eras[i];
                        }
                        break;

                    case 'NNNNN':
                        if (narrow === eraName) {
                            return eras[i];
                        }
                        break;
                }
            } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
                return eras[i];
            }
        }
    }

    function localeErasConvertYear(era, year) {
        var dir = era.since <= era.until ? +1 : -1;
        if (year === undefined) {
            return hooks(era.since).year();
        } else {
            return hooks(era.since).year() + (year - era.offset) * dir;
        }
    }

    function getEraName() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].name;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].name;
            }
        }

        return '';
    }

    function getEraNarrow() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].narrow;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].narrow;
            }
        }

        return '';
    }

    function getEraAbbr() {
        var i,
            l,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            // truncate time
            val = this.startOf('day').valueOf();

            if (eras[i].since <= val && val <= eras[i].until) {
                return eras[i].abbr;
            }
            if (eras[i].until <= val && val <= eras[i].since) {
                return eras[i].abbr;
            }
        }

        return '';
    }

    function getEraYear() {
        var i,
            l,
            dir,
            val,
            eras = this.localeData().eras();
        for (i = 0, l = eras.length; i < l; ++i) {
            dir = eras[i].since <= eras[i].until ? +1 : -1;

            // truncate time
            val = this.startOf('day').valueOf();

            if (
                (eras[i].since <= val && val <= eras[i].until) ||
                (eras[i].until <= val && val <= eras[i].since)
            ) {
                return (
                    (this.year() - hooks(eras[i].since).year()) * dir +
                    eras[i].offset
                );
            }
        }

        return this.year();
    }

    function erasNameRegex(isStrict) {
        if (!hasOwnProp(this, '_erasNameRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasNameRegex : this._erasRegex;
    }

    function erasAbbrRegex(isStrict) {
        if (!hasOwnProp(this, '_erasAbbrRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasAbbrRegex : this._erasRegex;
    }

    function erasNarrowRegex(isStrict) {
        if (!hasOwnProp(this, '_erasNarrowRegex')) {
            computeErasParse.call(this);
        }
        return isStrict ? this._erasNarrowRegex : this._erasRegex;
    }

    function matchEraAbbr(isStrict, locale) {
        return locale.erasAbbrRegex(isStrict);
    }

    function matchEraName(isStrict, locale) {
        return locale.erasNameRegex(isStrict);
    }

    function matchEraNarrow(isStrict, locale) {
        return locale.erasNarrowRegex(isStrict);
    }

    function matchEraYearOrdinal(isStrict, locale) {
        return locale._eraYearOrdinalRegex || matchUnsigned;
    }

    function computeErasParse() {
        var abbrPieces = [],
            namePieces = [],
            narrowPieces = [],
            mixedPieces = [],
            i,
            l,
            eras = this.eras();

        for (i = 0, l = eras.length; i < l; ++i) {
            namePieces.push(regexEscape(eras[i].name));
            abbrPieces.push(regexEscape(eras[i].abbr));
            narrowPieces.push(regexEscape(eras[i].narrow));

            mixedPieces.push(regexEscape(eras[i].name));
            mixedPieces.push(regexEscape(eras[i].abbr));
            mixedPieces.push(regexEscape(eras[i].narrow));
        }

        this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
        this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
        this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
        this._erasNarrowRegex = new RegExp(
            '^(' + narrowPieces.join('|') + ')',
            'i'
        );
    }

    // FORMATTING

    addFormatToken(0, ['gg', 2], 0, function () {
        return this.weekYear() % 100;
    });

    addFormatToken(0, ['GG', 2], 0, function () {
        return this.isoWeekYear() % 100;
    });

    function addWeekYearFormatToken(token, getter) {
        addFormatToken(0, [token, token.length], 0, getter);
    }

    addWeekYearFormatToken('gggg', 'weekYear');
    addWeekYearFormatToken('ggggg', 'weekYear');
    addWeekYearFormatToken('GGGG', 'isoWeekYear');
    addWeekYearFormatToken('GGGGG', 'isoWeekYear');

    // ALIASES

    addUnitAlias('weekYear', 'gg');
    addUnitAlias('isoWeekYear', 'GG');

    // PRIORITY

    addUnitPriority('weekYear', 1);
    addUnitPriority('isoWeekYear', 1);

    // PARSING

    addRegexToken('G', matchSigned);
    addRegexToken('g', matchSigned);
    addRegexToken('GG', match1to2, match2);
    addRegexToken('gg', match1to2, match2);
    addRegexToken('GGGG', match1to4, match4);
    addRegexToken('gggg', match1to4, match4);
    addRegexToken('GGGGG', match1to6, match6);
    addRegexToken('ggggg', match1to6, match6);

    addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (
        input,
        week,
        config,
        token
    ) {
        week[token.substr(0, 2)] = toInt(input);
    });

    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
        week[token] = hooks.parseTwoDigitYear(input);
    });

    // MOMENTS

    function getSetWeekYear(input) {
        return getSetWeekYearHelper.call(
            this,
            input,
            this.week(),
            this.weekday(),
            this.localeData()._week.dow,
            this.localeData()._week.doy
        );
    }

    function getSetISOWeekYear(input) {
        return getSetWeekYearHelper.call(
            this,
            input,
            this.isoWeek(),
            this.isoWeekday(),
            1,
            4
        );
    }

    function getISOWeeksInYear() {
        return weeksInYear(this.year(), 1, 4);
    }

    function getISOWeeksInISOWeekYear() {
        return weeksInYear(this.isoWeekYear(), 1, 4);
    }

    function getWeeksInYear() {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
    }

    function getWeeksInWeekYear() {
        var weekInfo = this.localeData()._week;
        return weeksInYear(this.weekYear(), weekInfo.dow, weekInfo.doy);
    }

    function getSetWeekYearHelper(input, week, weekday, dow, doy) {
        var weeksTarget;
        if (input == null) {
            return weekOfYear(this, dow, doy).year;
        } else {
            weeksTarget = weeksInYear(input, dow, doy);
            if (week > weeksTarget) {
                week = weeksTarget;
            }
            return setWeekAll.call(this, input, week, weekday, dow, doy);
        }
    }

    function setWeekAll(weekYear, week, weekday, dow, doy) {
        var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
            date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);

        this.year(date.getUTCFullYear());
        this.month(date.getUTCMonth());
        this.date(date.getUTCDate());
        return this;
    }

    // FORMATTING

    addFormatToken('Q', 0, 'Qo', 'quarter');

    // ALIASES

    addUnitAlias('quarter', 'Q');

    // PRIORITY

    addUnitPriority('quarter', 7);

    // PARSING

    addRegexToken('Q', match1);
    addParseToken('Q', function (input, array) {
        array[MONTH] = (toInt(input) - 1) * 3;
    });

    // MOMENTS

    function getSetQuarter(input) {
        return input == null
            ? Math.ceil((this.month() + 1) / 3)
            : this.month((input - 1) * 3 + (this.month() % 3));
    }

    // FORMATTING

    addFormatToken('D', ['DD', 2], 'Do', 'date');

    // ALIASES

    addUnitAlias('date', 'D');

    // PRIORITY
    addUnitPriority('date', 9);

    // PARSING

    addRegexToken('D', match1to2);
    addRegexToken('DD', match1to2, match2);
    addRegexToken('Do', function (isStrict, locale) {
        // TODO: Remove "ordinalParse" fallback in next major release.
        return isStrict
            ? locale._dayOfMonthOrdinalParse || locale._ordinalParse
            : locale._dayOfMonthOrdinalParseLenient;
    });

    addParseToken(['D', 'DD'], DATE);
    addParseToken('Do', function (input, array) {
        array[DATE] = toInt(input.match(match1to2)[0]);
    });

    // MOMENTS

    var getSetDayOfMonth = makeGetSet('Date', true);

    // FORMATTING

    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');

    // ALIASES

    addUnitAlias('dayOfYear', 'DDD');

    // PRIORITY
    addUnitPriority('dayOfYear', 4);

    // PARSING

    addRegexToken('DDD', match1to3);
    addRegexToken('DDDD', match3);
    addParseToken(['DDD', 'DDDD'], function (input, array, config) {
        config._dayOfYear = toInt(input);
    });

    // HELPERS

    // MOMENTS

    function getSetDayOfYear(input) {
        var dayOfYear =
            Math.round(
                (this.clone().startOf('day') - this.clone().startOf('year')) / 864e5
            ) + 1;
        return input == null ? dayOfYear : this.add(input - dayOfYear, 'd');
    }

    // FORMATTING

    addFormatToken('m', ['mm', 2], 0, 'minute');

    // ALIASES

    addUnitAlias('minute', 'm');

    // PRIORITY

    addUnitPriority('minute', 14);

    // PARSING

    addRegexToken('m', match1to2);
    addRegexToken('mm', match1to2, match2);
    addParseToken(['m', 'mm'], MINUTE);

    // MOMENTS

    var getSetMinute = makeGetSet('Minutes', false);

    // FORMATTING

    addFormatToken('s', ['ss', 2], 0, 'second');

    // ALIASES

    addUnitAlias('second', 's');

    // PRIORITY

    addUnitPriority('second', 15);

    // PARSING

    addRegexToken('s', match1to2);
    addRegexToken('ss', match1to2, match2);
    addParseToken(['s', 'ss'], SECOND);

    // MOMENTS

    var getSetSecond = makeGetSet('Seconds', false);

    // FORMATTING

    addFormatToken('S', 0, 0, function () {
        return ~~(this.millisecond() / 100);
    });

    addFormatToken(0, ['SS', 2], 0, function () {
        return ~~(this.millisecond() / 10);
    });

    addFormatToken(0, ['SSS', 3], 0, 'millisecond');
    addFormatToken(0, ['SSSS', 4], 0, function () {
        return this.millisecond() * 10;
    });
    addFormatToken(0, ['SSSSS', 5], 0, function () {
        return this.millisecond() * 100;
    });
    addFormatToken(0, ['SSSSSS', 6], 0, function () {
        return this.millisecond() * 1000;
    });
    addFormatToken(0, ['SSSSSSS', 7], 0, function () {
        return this.millisecond() * 10000;
    });
    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
        return this.millisecond() * 100000;
    });
    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
        return this.millisecond() * 1000000;
    });

    // ALIASES

    addUnitAlias('millisecond', 'ms');

    // PRIORITY

    addUnitPriority('millisecond', 16);

    // PARSING

    addRegexToken('S', match1to3, match1);
    addRegexToken('SS', match1to3, match2);
    addRegexToken('SSS', match1to3, match3);

    var token, getSetMillisecond;
    for (token = 'SSSS'; token.length <= 9; token += 'S') {
        addRegexToken(token, matchUnsigned);
    }

    function parseMs(input, array) {
        array[MILLISECOND] = toInt(('0.' + input) * 1000);
    }

    for (token = 'S'; token.length <= 9; token += 'S') {
        addParseToken(token, parseMs);
    }

    getSetMillisecond = makeGetSet('Milliseconds', false);

    // FORMATTING

    addFormatToken('z', 0, 0, 'zoneAbbr');
    addFormatToken('zz', 0, 0, 'zoneName');

    // MOMENTS

    function getZoneAbbr() {
        return this._isUTC ? 'UTC' : '';
    }

    function getZoneName() {
        return this._isUTC ? 'Coordinated Universal Time' : '';
    }

    var proto = Moment.prototype;

    proto.add = add;
    proto.calendar = calendar$1;
    proto.clone = clone;
    proto.diff = diff;
    proto.endOf = endOf;
    proto.format = format;
    proto.from = from;
    proto.fromNow = fromNow;
    proto.to = to;
    proto.toNow = toNow;
    proto.get = stringGet;
    proto.invalidAt = invalidAt;
    proto.isAfter = isAfter;
    proto.isBefore = isBefore;
    proto.isBetween = isBetween;
    proto.isSame = isSame;
    proto.isSameOrAfter = isSameOrAfter;
    proto.isSameOrBefore = isSameOrBefore;
    proto.isValid = isValid$2;
    proto.lang = lang;
    proto.locale = locale;
    proto.localeData = localeData;
    proto.max = prototypeMax;
    proto.min = prototypeMin;
    proto.parsingFlags = parsingFlags;
    proto.set = stringSet;
    proto.startOf = startOf;
    proto.subtract = subtract;
    proto.toArray = toArray;
    proto.toObject = toObject;
    proto.toDate = toDate;
    proto.toISOString = toISOString;
    proto.inspect = inspect;
    if (typeof Symbol !== 'undefined' && Symbol.for != null) {
        proto[Symbol.for('nodejs.util.inspect.custom')] = function () {
            return 'Moment<' + this.format() + '>';
        };
    }
    proto.toJSON = toJSON;
    proto.toString = toString;
    proto.unix = unix;
    proto.valueOf = valueOf;
    proto.creationData = creationData;
    proto.eraName = getEraName;
    proto.eraNarrow = getEraNarrow;
    proto.eraAbbr = getEraAbbr;
    proto.eraYear = getEraYear;
    proto.year = getSetYear;
    proto.isLeapYear = getIsLeapYear;
    proto.weekYear = getSetWeekYear;
    proto.isoWeekYear = getSetISOWeekYear;
    proto.quarter = proto.quarters = getSetQuarter;
    proto.month = getSetMonth;
    proto.daysInMonth = getDaysInMonth;
    proto.week = proto.weeks = getSetWeek;
    proto.isoWeek = proto.isoWeeks = getSetISOWeek;
    proto.weeksInYear = getWeeksInYear;
    proto.weeksInWeekYear = getWeeksInWeekYear;
    proto.isoWeeksInYear = getISOWeeksInYear;
    proto.isoWeeksInISOWeekYear = getISOWeeksInISOWeekYear;
    proto.date = getSetDayOfMonth;
    proto.day = proto.days = getSetDayOfWeek;
    proto.weekday = getSetLocaleDayOfWeek;
    proto.isoWeekday = getSetISODayOfWeek;
    proto.dayOfYear = getSetDayOfYear;
    proto.hour = proto.hours = getSetHour;
    proto.minute = proto.minutes = getSetMinute;
    proto.second = proto.seconds = getSetSecond;
    proto.millisecond = proto.milliseconds = getSetMillisecond;
    proto.utcOffset = getSetOffset;
    proto.utc = setOffsetToUTC;
    proto.local = setOffsetToLocal;
    proto.parseZone = setOffsetToParsedOffset;
    proto.hasAlignedHourOffset = hasAlignedHourOffset;
    proto.isDST = isDaylightSavingTime;
    proto.isLocal = isLocal;
    proto.isUtcOffset = isUtcOffset;
    proto.isUtc = isUtc;
    proto.isUTC = isUtc;
    proto.zoneAbbr = getZoneAbbr;
    proto.zoneName = getZoneName;
    proto.dates = deprecate(
        'dates accessor is deprecated. Use date instead.',
        getSetDayOfMonth
    );
    proto.months = deprecate(
        'months accessor is deprecated. Use month instead',
        getSetMonth
    );
    proto.years = deprecate(
        'years accessor is deprecated. Use year instead',
        getSetYear
    );
    proto.zone = deprecate(
        'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/',
        getSetZone
    );
    proto.isDSTShifted = deprecate(
        'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information',
        isDaylightSavingTimeShifted
    );

    function createUnix(input) {
        return createLocal(input * 1000);
    }

    function createInZone() {
        return createLocal.apply(null, arguments).parseZone();
    }

    function preParsePostFormat(string) {
        return string;
    }

    var proto$1 = Locale.prototype;

    proto$1.calendar = calendar;
    proto$1.longDateFormat = longDateFormat;
    proto$1.invalidDate = invalidDate;
    proto$1.ordinal = ordinal;
    proto$1.preparse = preParsePostFormat;
    proto$1.postformat = preParsePostFormat;
    proto$1.relativeTime = relativeTime;
    proto$1.pastFuture = pastFuture;
    proto$1.set = set;
    proto$1.eras = localeEras;
    proto$1.erasParse = localeErasParse;
    proto$1.erasConvertYear = localeErasConvertYear;
    proto$1.erasAbbrRegex = erasAbbrRegex;
    proto$1.erasNameRegex = erasNameRegex;
    proto$1.erasNarrowRegex = erasNarrowRegex;

    proto$1.months = localeMonths;
    proto$1.monthsShort = localeMonthsShort;
    proto$1.monthsParse = localeMonthsParse;
    proto$1.monthsRegex = monthsRegex;
    proto$1.monthsShortRegex = monthsShortRegex;
    proto$1.week = localeWeek;
    proto$1.firstDayOfYear = localeFirstDayOfYear;
    proto$1.firstDayOfWeek = localeFirstDayOfWeek;

    proto$1.weekdays = localeWeekdays;
    proto$1.weekdaysMin = localeWeekdaysMin;
    proto$1.weekdaysShort = localeWeekdaysShort;
    proto$1.weekdaysParse = localeWeekdaysParse;

    proto$1.weekdaysRegex = weekdaysRegex;
    proto$1.weekdaysShortRegex = weekdaysShortRegex;
    proto$1.weekdaysMinRegex = weekdaysMinRegex;

    proto$1.isPM = localeIsPM;
    proto$1.meridiem = localeMeridiem;

    function get$1(format, index, field, setter) {
        var locale = getLocale(),
            utc = createUTC().set(setter, index);
        return locale[field](utc, format);
    }

    function listMonthsImpl(format, index, field) {
        if (isNumber(format)) {
            index = format;
            format = undefined;
        }

        format = format || '';

        if (index != null) {
            return get$1(format, index, field, 'month');
        }

        var i,
            out = [];
        for (i = 0; i < 12; i++) {
            out[i] = get$1(format, i, field, 'month');
        }
        return out;
    }

    // ()
    // (5)
    // (fmt, 5)
    // (fmt)
    // (true)
    // (true, 5)
    // (true, fmt, 5)
    // (true, fmt)
    function listWeekdaysImpl(localeSorted, format, index, field) {
        if (typeof localeSorted === 'boolean') {
            if (isNumber(format)) {
                index = format;
                format = undefined;
            }

            format = format || '';
        } else {
            format = localeSorted;
            index = format;
            localeSorted = false;

            if (isNumber(format)) {
                index = format;
                format = undefined;
            }

            format = format || '';
        }

        var locale = getLocale(),
            shift = localeSorted ? locale._week.dow : 0,
            i,
            out = [];

        if (index != null) {
            return get$1(format, (index + shift) % 7, field, 'day');
        }

        for (i = 0; i < 7; i++) {
            out[i] = get$1(format, (i + shift) % 7, field, 'day');
        }
        return out;
    }

    function listMonths(format, index) {
        return listMonthsImpl(format, index, 'months');
    }

    function listMonthsShort(format, index) {
        return listMonthsImpl(format, index, 'monthsShort');
    }

    function listWeekdays(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
    }

    function listWeekdaysShort(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
    }

    function listWeekdaysMin(localeSorted, format, index) {
        return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
    }

    getSetGlobalLocale('en', {
        eras: [
            {
                since: '0001-01-01',
                until: +Infinity,
                offset: 1,
                name: 'Anno Domini',
                narrow: 'AD',
                abbr: 'AD',
            },
            {
                since: '0000-12-31',
                until: -Infinity,
                offset: 1,
                name: 'Before Christ',
                narrow: 'BC',
                abbr: 'BC',
            },
        ],
        dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
        ordinal: function (number) {
            var b = number % 10,
                output =
                    toInt((number % 100) / 10) === 1
                        ? 'th'
                        : b === 1
                        ? 'st'
                        : b === 2
                        ? 'nd'
                        : b === 3
                        ? 'rd'
                        : 'th';
            return number + output;
        },
    });

    // Side effect imports

    hooks.lang = deprecate(
        'moment.lang is deprecated. Use moment.locale instead.',
        getSetGlobalLocale
    );
    hooks.langData = deprecate(
        'moment.langData is deprecated. Use moment.localeData instead.',
        getLocale
    );

    var mathAbs = Math.abs;

    function abs() {
        var data = this._data;

        this._milliseconds = mathAbs(this._milliseconds);
        this._days = mathAbs(this._days);
        this._months = mathAbs(this._months);

        data.milliseconds = mathAbs(data.milliseconds);
        data.seconds = mathAbs(data.seconds);
        data.minutes = mathAbs(data.minutes);
        data.hours = mathAbs(data.hours);
        data.months = mathAbs(data.months);
        data.years = mathAbs(data.years);

        return this;
    }

    function addSubtract$1(duration, input, value, direction) {
        var other = createDuration(input, value);

        duration._milliseconds += direction * other._milliseconds;
        duration._days += direction * other._days;
        duration._months += direction * other._months;

        return duration._bubble();
    }

    // supports only 2.0-style add(1, 's') or add(duration)
    function add$1(input, value) {
        return addSubtract$1(this, input, value, 1);
    }

    // supports only 2.0-style subtract(1, 's') or subtract(duration)
    function subtract$1(input, value) {
        return addSubtract$1(this, input, value, -1);
    }

    function absCeil(number) {
        if (number < 0) {
            return Math.floor(number);
        } else {
            return Math.ceil(number);
        }
    }

    function bubble() {
        var milliseconds = this._milliseconds,
            days = this._days,
            months = this._months,
            data = this._data,
            seconds,
            minutes,
            hours,
            years,
            monthsFromDays;

        // if we have a mix of positive and negative values, bubble down first
        // check: https://github.com/moment/moment/issues/2166
        if (
            !(
                (milliseconds >= 0 && days >= 0 && months >= 0) ||
                (milliseconds <= 0 && days <= 0 && months <= 0)
            )
        ) {
            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
            days = 0;
            months = 0;
        }

        // The following code bubbles up values, see the tests for
        // examples of what that means.
        data.milliseconds = milliseconds % 1000;

        seconds = absFloor(milliseconds / 1000);
        data.seconds = seconds % 60;

        minutes = absFloor(seconds / 60);
        data.minutes = minutes % 60;

        hours = absFloor(minutes / 60);
        data.hours = hours % 24;

        days += absFloor(hours / 24);

        // convert days to months
        monthsFromDays = absFloor(daysToMonths(days));
        months += monthsFromDays;
        days -= absCeil(monthsToDays(monthsFromDays));

        // 12 months -> 1 year
        years = absFloor(months / 12);
        months %= 12;

        data.days = days;
        data.months = months;
        data.years = years;

        return this;
    }

    function daysToMonths(days) {
        // 400 years have 146097 days (taking into account leap year rules)
        // 400 years have 12 months === 4800
        return (days * 4800) / 146097;
    }

    function monthsToDays(months) {
        // the reverse of daysToMonths
        return (months * 146097) / 4800;
    }

    function as(units) {
        if (!this.isValid()) {
            return NaN;
        }
        var days,
            months,
            milliseconds = this._milliseconds;

        units = normalizeUnits(units);

        if (units === 'month' || units === 'quarter' || units === 'year') {
            days = this._days + milliseconds / 864e5;
            months = this._months + daysToMonths(days);
            switch (units) {
                case 'month':
                    return months;
                case 'quarter':
                    return months / 3;
                case 'year':
                    return months / 12;
            }
        } else {
            // handle milliseconds separately because of floating point math errors (issue #1867)
            days = this._days + Math.round(monthsToDays(this._months));
            switch (units) {
                case 'week':
                    return days / 7 + milliseconds / 6048e5;
                case 'day':
                    return days + milliseconds / 864e5;
                case 'hour':
                    return days * 24 + milliseconds / 36e5;
                case 'minute':
                    return days * 1440 + milliseconds / 6e4;
                case 'second':
                    return days * 86400 + milliseconds / 1000;
                // Math.floor prevents floating point math errors here
                case 'millisecond':
                    return Math.floor(days * 864e5) + milliseconds;
                default:
                    throw new Error('Unknown unit ' + units);
            }
        }
    }

    // TODO: Use this.as('ms')?
    function valueOf$1() {
        if (!this.isValid()) {
            return NaN;
        }
        return (
            this._milliseconds +
            this._days * 864e5 +
            (this._months % 12) * 2592e6 +
            toInt(this._months / 12) * 31536e6
        );
    }

    function makeAs(alias) {
        return function () {
            return this.as(alias);
        };
    }

    var asMilliseconds = makeAs('ms'),
        asSeconds = makeAs('s'),
        asMinutes = makeAs('m'),
        asHours = makeAs('h'),
        asDays = makeAs('d'),
        asWeeks = makeAs('w'),
        asMonths = makeAs('M'),
        asQuarters = makeAs('Q'),
        asYears = makeAs('y');

    function clone$1() {
        return createDuration(this);
    }

    function get$2(units) {
        units = normalizeUnits(units);
        return this.isValid() ? this[units + 's']() : NaN;
    }

    function makeGetter(name) {
        return function () {
            return this.isValid() ? this._data[name] : NaN;
        };
    }

    var milliseconds = makeGetter('milliseconds'),
        seconds = makeGetter('seconds'),
        minutes = makeGetter('minutes'),
        hours = makeGetter('hours'),
        days = makeGetter('days'),
        months = makeGetter('months'),
        years = makeGetter('years');

    function weeks() {
        return absFloor(this.days() / 7);
    }

    var round = Math.round,
        thresholds = {
            ss: 44, // a few seconds to seconds
            s: 45, // seconds to minute
            m: 45, // minutes to hour
            h: 22, // hours to day
            d: 26, // days to month/week
            w: null, // weeks to month
            M: 11, // months to year
        };

    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
    }

    function relativeTime$1(posNegDuration, withoutSuffix, thresholds, locale) {
        var duration = createDuration(posNegDuration).abs(),
            seconds = round(duration.as('s')),
            minutes = round(duration.as('m')),
            hours = round(duration.as('h')),
            days = round(duration.as('d')),
            months = round(duration.as('M')),
            weeks = round(duration.as('w')),
            years = round(duration.as('y')),
            a =
                (seconds <= thresholds.ss && ['s', seconds]) ||
                (seconds < thresholds.s && ['ss', seconds]) ||
                (minutes <= 1 && ['m']) ||
                (minutes < thresholds.m && ['mm', minutes]) ||
                (hours <= 1 && ['h']) ||
                (hours < thresholds.h && ['hh', hours]) ||
                (days <= 1 && ['d']) ||
                (days < thresholds.d && ['dd', days]);

        if (thresholds.w != null) {
            a =
                a ||
                (weeks <= 1 && ['w']) ||
                (weeks < thresholds.w && ['ww', weeks]);
        }
        a = a ||
            (months <= 1 && ['M']) ||
            (months < thresholds.M && ['MM', months]) ||
            (years <= 1 && ['y']) || ['yy', years];

        a[2] = withoutSuffix;
        a[3] = +posNegDuration > 0;
        a[4] = locale;
        return substituteTimeAgo.apply(null, a);
    }

    // This function allows you to set the rounding function for relative time strings
    function getSetRelativeTimeRounding(roundingFunction) {
        if (roundingFunction === undefined) {
            return round;
        }
        if (typeof roundingFunction === 'function') {
            round = roundingFunction;
            return true;
        }
        return false;
    }

    // This function allows you to set a threshold for relative time strings
    function getSetRelativeTimeThreshold(threshold, limit) {
        if (thresholds[threshold] === undefined) {
            return false;
        }
        if (limit === undefined) {
            return thresholds[threshold];
        }
        thresholds[threshold] = limit;
        if (threshold === 's') {
            thresholds.ss = limit - 1;
        }
        return true;
    }

    function humanize(argWithSuffix, argThresholds) {
        if (!this.isValid()) {
            return this.localeData().invalidDate();
        }

        var withSuffix = false,
            th = thresholds,
            locale,
            output;

        if (typeof argWithSuffix === 'object') {
            argThresholds = argWithSuffix;
            argWithSuffix = false;
        }
        if (typeof argWithSuffix === 'boolean') {
            withSuffix = argWithSuffix;
        }
        if (typeof argThresholds === 'object') {
            th = Object.assign({}, thresholds, argThresholds);
            if (argThresholds.s != null && argThresholds.ss == null) {
                th.ss = argThresholds.s - 1;
            }
        }

        locale = this.localeData();
        output = relativeTime$1(this, !withSuffix, th, locale);

        if (withSuffix) {
            output = locale.pastFuture(+this, output);
        }

        return locale.postformat(output);
    }

    var abs$1 = Math.abs;

    function sign(x) {
        return (x > 0) - (x < 0) || +x;
    }

    function toISOString$1() {
        // for ISO strings we do not use the normal bubbling rules:
        //  * milliseconds bubble up until they become hours
        //  * days do not bubble at all
        //  * months bubble up until they become years
        // This is because there is no context-free conversion between hours and days
        // (think of clock changes)
        // and also not between days and months (28-31 days per month)
        if (!this.isValid()) {
            return this.localeData().invalidDate();
        }

        var seconds = abs$1(this._milliseconds) / 1000,
            days = abs$1(this._days),
            months = abs$1(this._months),
            minutes,
            hours,
            years,
            s,
            total = this.asSeconds(),
            totalSign,
            ymSign,
            daysSign,
            hmsSign;

        if (!total) {
            // this is the same as C#'s (Noda) and python (isodate)...
            // but not other JS (goog.date)
            return 'P0D';
        }

        // 3600 seconds -> 60 minutes -> 1 hour
        minutes = absFloor(seconds / 60);
        hours = absFloor(minutes / 60);
        seconds %= 60;
        minutes %= 60;

        // 12 months -> 1 year
        years = absFloor(months / 12);
        months %= 12;

        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
        s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';

        totalSign = total < 0 ? '-' : '';
        ymSign = sign(this._months) !== sign(total) ? '-' : '';
        daysSign = sign(this._days) !== sign(total) ? '-' : '';
        hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';

        return (
            totalSign +
            'P' +
            (years ? ymSign + years + 'Y' : '') +
            (months ? ymSign + months + 'M' : '') +
            (days ? daysSign + days + 'D' : '') +
            (hours || minutes || seconds ? 'T' : '') +
            (hours ? hmsSign + hours + 'H' : '') +
            (minutes ? hmsSign + minutes + 'M' : '') +
            (seconds ? hmsSign + s + 'S' : '')
        );
    }

    var proto$2 = Duration.prototype;

    proto$2.isValid = isValid$1;
    proto$2.abs = abs;
    proto$2.add = add$1;
    proto$2.subtract = subtract$1;
    proto$2.as = as;
    proto$2.asMilliseconds = asMilliseconds;
    proto$2.asSeconds = asSeconds;
    proto$2.asMinutes = asMinutes;
    proto$2.asHours = asHours;
    proto$2.asDays = asDays;
    proto$2.asWeeks = asWeeks;
    proto$2.asMonths = asMonths;
    proto$2.asQuarters = asQuarters;
    proto$2.asYears = asYears;
    proto$2.valueOf = valueOf$1;
    proto$2._bubble = bubble;
    proto$2.clone = clone$1;
    proto$2.get = get$2;
    proto$2.milliseconds = milliseconds;
    proto$2.seconds = seconds;
    proto$2.minutes = minutes;
    proto$2.hours = hours;
    proto$2.days = days;
    proto$2.weeks = weeks;
    proto$2.months = months;
    proto$2.years = years;
    proto$2.humanize = humanize;
    proto$2.toISOString = toISOString$1;
    proto$2.toString = toISOString$1;
    proto$2.toJSON = toISOString$1;
    proto$2.locale = locale;
    proto$2.localeData = localeData;

    proto$2.toIsoString = deprecate(
        'toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)',
        toISOString$1
    );
    proto$2.lang = lang;

    // FORMATTING

    addFormatToken('X', 0, 0, 'unix');
    addFormatToken('x', 0, 0, 'valueOf');

    // PARSING

    addRegexToken('x', matchSigned);
    addRegexToken('X', matchTimestamp);
    addParseToken('X', function (input, array, config) {
        config._d = new Date(parseFloat(input) * 1000);
    });
    addParseToken('x', function (input, array, config) {
        config._d = new Date(toInt(input));
    });

    //! moment.js

    hooks.version = '2.27.0';

    setHookCallback(createLocal);

    hooks.fn = proto;
    hooks.min = min;
    hooks.max = max;
    hooks.now = now;
    hooks.utc = createUTC;
    hooks.unix = createUnix;
    hooks.months = listMonths;
    hooks.isDate = isDate;
    hooks.locale = getSetGlobalLocale;
    hooks.invalid = createInvalid;
    hooks.duration = createDuration;
    hooks.isMoment = isMoment;
    hooks.weekdays = listWeekdays;
    hooks.parseZone = createInZone;
    hooks.localeData = getLocale;
    hooks.isDuration = isDuration;
    hooks.monthsShort = listMonthsShort;
    hooks.weekdaysMin = listWeekdaysMin;
    hooks.defineLocale = defineLocale;
    hooks.updateLocale = updateLocale;
    hooks.locales = listLocales;
    hooks.weekdaysShort = listWeekdaysShort;
    hooks.normalizeUnits = normalizeUnits;
    hooks.relativeTimeRounding = getSetRelativeTimeRounding;
    hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;
    hooks.calendarFormat = getCalendarFormat;
    hooks.prototype = proto;

    // currently HTML5 input type only supports 24-hour formats
    hooks.HTML5_FMT = {
        DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" />
        DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" />
        DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" />
        DATE: 'YYYY-MM-DD', // <input type="date" />
        TIME: 'HH:mm', // <input type="time" />
        TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" />
        TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" />
        WEEK: 'GGGG-[W]WW', // <input type="week" />
        MONTH: 'YYYY-MM', // <input type="month" />
    };

    return hooks;

})));

},{}],220:[function(require,module,exports){
/*! @preserve
 * numeral.js
 * version : 1.5.6
 * author : Adam Draper
 * license : MIT
 * http://adamwdraper.github.com/Numeral-js/
 */

(function() {

    /************************************
        Variables
    ************************************/

    var numeral,
        VERSION = '1.5.6',
        // internal storage for language config files
        languages = {},
        defaults = {
            currentLanguage: 'en',
            zeroFormat: null,
            nullFormat: null,
            defaultFormat: '0,0'
        },
        options = {
            currentLanguage: defaults.currentLanguage,
            zeroFormat: defaults.zeroFormat,
            nullFormat: defaults.nullFormat,
            defaultFormat: defaults.defaultFormat
        },
        byteSuffixes = {
            bytes: ['B','KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
            iec: ['B','KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
        };


    /************************************
        Constructors
    ************************************/


    // Numeral prototype object
    function Numeral(number) {
        this._value = number;
    }

    /**
     * Implementation of toFixed() that treats floats more like decimals
     *
     * Fixes binary rounding issues (eg. (0.615).toFixed(2) === '0.61') that present
     * problems for accounting- and finance-related software.
     */
    function toFixed (value, maxDecimals, roundingFunction, optionals) {
        var splitValue = value.toString().split('.'),
            minDecimals = maxDecimals - (optionals || 0),
            boundedPrecision,
            optionalsRegExp,
            power,
            output;

        // Use the smallest precision value possible to avoid errors from floating point representation
        if (splitValue.length === 2) {
          boundedPrecision = Math.min(Math.max(splitValue[1].length, minDecimals), maxDecimals);
        } else {
          boundedPrecision = minDecimals;
        }

        power = Math.pow(10, boundedPrecision);

        //roundingFunction = (roundingFunction !== undefined ? roundingFunction : Math.round);
        // Multiply up by precision, round accurately, then divide and use native toFixed():
        output = (roundingFunction(value * power) / power).toFixed(boundedPrecision);

        if (optionals > maxDecimals - boundedPrecision) {
            optionalsRegExp = new RegExp('\\.?0{1,' + (optionals - (maxDecimals - boundedPrecision)) + '}$');
            output = output.replace(optionalsRegExp, '');
        }

        return output;
    }

    /************************************
        Formatting
    ************************************/

    // determine what type of formatting we need to do
    function formatNumeral(n, format, roundingFunction) {
        var output;

        if (n._value === 0 && options.zeroFormat !== null) {
            output = options.zeroFormat;
        } else if (n._value === null && options.nullFormat !== null) {
            output = options.nullFormat;
        } else {
            // figure out what kind of format we are dealing with
            if (format.indexOf('$') > -1) {
                output = formatCurrency(n, format, roundingFunction);
            } else if (format.indexOf('%') > -1) {
                output = formatPercentage(n, format, roundingFunction);
            } else if (format.indexOf(':') > -1) {
                output = formatTime(n, format);
            } else if (format.indexOf('b') > -1 || format.indexOf('ib') > -1) {
                output = formatBytes(n, format, roundingFunction);
            } else if (format.indexOf('o') > -1) {
                output = formatOrdinal(n, format, roundingFunction);
            } else {
                output = formatNumber(n._value, format, roundingFunction);
            }
        }

        return output;
    }

    function formatCurrency(n, format, roundingFunction) {
        var symbolIndex = format.indexOf('$'),
            openParenIndex = format.indexOf('('),
            minusSignIndex = format.indexOf('-'),
            space = '',
            spliceIndex,
            output;

        // check for space before or after currency
        if (format.indexOf(' $') > -1) {
            space = ' ';
            format = format.replace(' $', '');
        } else if (format.indexOf('$ ') > -1) {
            space = ' ';
            format = format.replace('$ ', '');
        } else {
            format = format.replace('$', '');
        }

        // format the number
        output = formatNumber(n._value, format, roundingFunction, false);

        // position the symbol
        if (symbolIndex <= 1) {
            if (output.indexOf('(') > -1 || output.indexOf('-') > -1) {
                output = output.split('');
                spliceIndex = 1;
                if (symbolIndex < openParenIndex || symbolIndex < minusSignIndex) {
                    // the symbol appears before the "(" or "-"
                    spliceIndex = 0;
                }
                output.splice(spliceIndex, 0, languages[options.currentLanguage].currency.symbol + space);
                output = output.join('');
            } else {
                output = languages[options.currentLanguage].currency.symbol + space + output;
            }
        } else {
            if (output.indexOf(')') > -1) {
                output = output.split('');
                output.splice(-1, 0, space + languages[options.currentLanguage].currency.symbol);
                output = output.join('');
            } else {
                output = output + space + languages[options.currentLanguage].currency.symbol;
            }
        }

        return output;
    }

    function formatPercentage(n, format, roundingFunction) {
        var space = '',
            output,
            value = n._value * 100;

        // check for space before %
        if (format.indexOf(' %') > -1) {
            space = ' ';
            format = format.replace(' %', '');
        } else {
            format = format.replace('%', '');
        }

        output = formatNumber(value, format, roundingFunction);

        if (output.indexOf(')') > -1) {
            output = output.split('');
            output.splice(-1, 0, space + '%');
            output = output.join('');
        } else {
            output = output + space + '%';
        }

        return output;
    }

    function formatBytes(n, format, roundingFunction) {
        var output,
            suffixes = format.indexOf('ib') > -1 ? byteSuffixes.iec : byteSuffixes.bytes,
            value = n._value,
            suffix = '',
            power,
            min,
            max;

        // check for space before
        if (format.indexOf(' b') > -1 || format.indexOf(' ib') > -1) {
            suffix = ' ';
            format = format.replace(' ib', '').replace(' b', '');
        } else {
            format = format.replace('ib', '').replace('b', '');
        }

        for (power = 0; power <= suffixes.length; power++) {
            min = Math.pow(1024, power);
            max = Math.pow(1024, power + 1);

            if (value === null || value === 0 || value >= min && value < max) {
                suffix += suffixes[power];

                if (min > 0) {
                    value = value / min;
                }

                break;
            }
        }

        output = formatNumber(value, format, roundingFunction);

        return output + suffix;
    }

    function formatOrdinal(n, format, roundingFunction) {
        var output,
            ordinal = '';

        // check for space before
        if (format.indexOf(' o') > -1) {
            ordinal = ' ';
            format = format.replace(' o', '');
        } else {
            format = format.replace('o', '');
        }

        ordinal += languages[options.currentLanguage].ordinal(n._value);

        output = formatNumber(n._value, format, roundingFunction);

        return output + ordinal;
    }

    function formatTime(n) {
        var hours = Math.floor(n._value / 60 / 60),
            minutes = Math.floor((n._value - (hours * 60 * 60)) / 60),
            seconds = Math.round(n._value - (hours * 60 * 60) - (minutes * 60));

        return hours + ':' + ((minutes < 10) ? '0' + minutes : minutes) + ':' + ((seconds < 10) ? '0' + seconds : seconds);
    }

    function formatNumber(value, format, roundingFunction) {
        var negP = false,
            signed = false,
            optDec = false,
            abbr = '',
            abbrK = false, // force abbreviation to thousands
            abbrM = false, // force abbreviation to millions
            abbrB = false, // force abbreviation to billions
            abbrT = false, // force abbreviation to trillions
            abbrForce = false, // force abbreviation
            abs,
            min,
            max,
            power,
            w,
            precision,
            thousands,
            d = '',
            neg = false;

        if (value === null) {
            value = 0;
        }

        abs = Math.abs(value);

        // see if we should use parentheses for negative number or if we should prefix with a sign
        // if both are present we default to parentheses
        if (format.indexOf('(') > -1) {
            negP = true;
            format = format.slice(1, -1);
        } else if (format.indexOf('+') > -1) {
            signed = true;
            format = format.replace(/\+/g, '');
        }

        // see if abbreviation is wanted
        if (format.indexOf('a') > -1) {
            // check if abbreviation is specified
            abbrK = format.indexOf('aK') >= 0;
            abbrM = format.indexOf('aM') >= 0;
            abbrB = format.indexOf('aB') >= 0;
            abbrT = format.indexOf('aT') >= 0;
            abbrForce = abbrK || abbrM || abbrB || abbrT;

            // check for space before abbreviation
            if (format.indexOf(' a') > -1) {
                abbr = ' ';
            }

            format = format.replace(new RegExp(abbr + 'a[KMBT]?'), '');

            if (abs >= Math.pow(10, 12) && !abbrForce || abbrT) {
                // trillion
                abbr = abbr + languages[options.currentLanguage].abbreviations.trillion;
                value = value / Math.pow(10, 12);
            } else if (abs < Math.pow(10, 12) && abs >= Math.pow(10, 9) && !abbrForce || abbrB) {
                // billion
                abbr = abbr + languages[options.currentLanguage].abbreviations.billion;
                value = value / Math.pow(10, 9);
            } else if (abs < Math.pow(10, 9) && abs >= Math.pow(10, 6) && !abbrForce || abbrM) {
                // million
                abbr = abbr + languages[options.currentLanguage].abbreviations.million;
                value = value / Math.pow(10, 6);
            } else if (abs < Math.pow(10, 6) && abs >= Math.pow(10, 3) && !abbrForce || abbrK) {
                // thousand
                abbr = abbr + languages[options.currentLanguage].abbreviations.thousand;
                value = value / Math.pow(10, 3);
            }
        }


        if (format.indexOf('[.]') > -1) {
            optDec = true;
            format = format.replace('[.]', '.');
        }

        w = value.toString().split('.')[0];
        precision = format.split('.')[1];
        thousands = format.indexOf(',');

        if (precision) {
            if (precision.indexOf('[') > -1) {
                precision = precision.replace(']', '');
                precision = precision.split('[');
                d = toFixed(value, (precision[0].length + precision[1].length), roundingFunction, precision[1].length);
            } else {
                d = toFixed(value, precision.length, roundingFunction);
            }

            w = d.split('.')[0];

            if (d.indexOf('.') > -1) {
                d = languages[options.currentLanguage].delimiters.decimal + d.split('.')[1];
            } else {
                d = '';
            }

            if (optDec && Number(d.slice(1)) === 0) {
                d = '';
            }
        } else {
            w = toFixed(value, null, roundingFunction);
        }

        // format number
        if (w.indexOf('-') > -1) {
            w = w.slice(1);
            neg = true;
        }

        if (thousands > -1) {
            w = w.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + languages[options.currentLanguage].delimiters.thousands);
        }

        if (format.indexOf('.') === 0) {
            w = '';
        }

        return ((negP && neg) ? '(' : '') + ((!negP && neg) ? '-' : '') + ((!neg && signed) ? '+' : '') + w + d + ((abbr) ? abbr : '') + ((negP && neg) ? ')' : '');
    }


    /************************************
        Unformatting
    ************************************/

    // revert to number
    function unformatNumeral(n, string) {
        var stringOriginal = string,
            thousandRegExp,
            millionRegExp,
            billionRegExp,
            trillionRegExp,
            bytesMultiplier = false,
            power,
            value;

        if (string.indexOf(':') > -1) {
            value = unformatTime(string);
        } else {
            if (string === options.zeroFormat || string === options.nullFormat) {
                value = 0;
            } else {
                if (languages[options.currentLanguage].delimiters.decimal !== '.') {
                    string = string.replace(/\./g, '').replace(languages[options.currentLanguage].delimiters.decimal, '.');
                }

                // see if abbreviations are there so that we can multiply to the correct number
                thousandRegExp = new RegExp('[^a-zA-Z]' + languages[options.currentLanguage].abbreviations.thousand + '(?:\\)|(\\' + languages[options.currentLanguage].currency.symbol + ')?(?:\\))?)?$');
                millionRegExp = new RegExp('[^a-zA-Z]' + languages[options.currentLanguage].abbreviations.million + '(?:\\)|(\\' + languages[options.currentLanguage].currency.symbol + ')?(?:\\))?)?$');
                billionRegExp = new RegExp('[^a-zA-Z]' + languages[options.currentLanguage].abbreviations.billion + '(?:\\)|(\\' + languages[options.currentLanguage].currency.symbol + ')?(?:\\))?)?$');
                trillionRegExp = new RegExp('[^a-zA-Z]' + languages[options.currentLanguage].abbreviations.trillion + '(?:\\)|(\\' + languages[options.currentLanguage].currency.symbol + ')?(?:\\))?)?$');

                // see if bytes are there so that we can multiply to the correct number
                for (power = 1; power <= byteSuffixes.bytes.length; power++) {
                    bytesMultiplier = ((string.indexOf(byteSuffixes.bytes[power]) > -1) || (string.indexOf(byteSuffixes.iec[power]) > -1))? Math.pow(1024, power) : false;

                    if (bytesMultiplier) {
                        break;
                    }
                }

                // do some math to create our number
                value = bytesMultiplier ? bytesMultiplier : 1;
                value *= stringOriginal.match(thousandRegExp) ? Math.pow(10, 3) : 1;
                value *= stringOriginal.match(millionRegExp) ? Math.pow(10, 6) : 1;
                value *= stringOriginal.match(billionRegExp) ? Math.pow(10, 9) : 1;
                value *= stringOriginal.match(trillionRegExp) ? Math.pow(10, 12) : 1;
                // check for percentage
                value *= string.indexOf('%') > -1 ? 0.01 : 1;
                // check for negative number
                value *= (string.split('-').length + Math.min(string.split('(').length - 1, string.split(')').length - 1)) % 2 ? 1 : -1;
                // remove non numbers
                value *= Number(string.replace(/[^0-9\.]+/g, ''));
                // round if we are talking about bytes
                value = bytesMultiplier ? Math.ceil(value) : value;
            }
        }

        n._value = value;

        return n._value;
    }
    function unformatTime(string) {
        var timeArray = string.split(':'),
            seconds = 0;
        // turn hours and minutes into seconds and add them all up
        if (timeArray.length === 3) {
            // hours
            seconds = seconds + (Number(timeArray[0]) * 60 * 60);
            // minutes
            seconds = seconds + (Number(timeArray[1]) * 60);
            // seconds
            seconds = seconds + Number(timeArray[2]);
        } else if (timeArray.length === 2) {
            // minutes
            seconds = seconds + (Number(timeArray[0]) * 60);
            // seconds
            seconds = seconds + Number(timeArray[1]);
        }
        return Number(seconds);
    }


    /************************************
        Top Level Functions
    ************************************/

    numeral = function(input) {
        if (numeral.isNumeral(input)) {
            input = input.value();
        } else if (input === 0 || typeof input === 'undefined') {
            input = 0;
        } else if (input === null) {
            input = null;
        } else if (!Number(input)) {
            input = numeral.fn.unformat(input);
        } else {
            input = Number(input);
        }

        return new Numeral(input);
    };

    // version number
    numeral.version = VERSION;

    // compare numeral object
    numeral.isNumeral = function(obj) {
        return obj instanceof Numeral;
    };


    // This function will load languages and then set the global language.  If
    // no arguments are passed in, it will simply return the current global
    // language key.
    numeral.language = function(key, values) {
        if (!key) {
            return options.currentLanguage;
        }

        key = key.toLowerCase();

        if (key && !values) {
            if (!languages[key]) {
                throw new Error('Unknown language : ' + key);
            }

            options.currentLanguage = key;
        }

        if (values || !languages[key]) {
            loadLanguage(key, values);
        }

        return numeral;
    };

    numeral.reset = function() {
        for (var property in defaults) {
            options[property] = defaults[property];
        }
    };

    // This function provides access to the loaded language data.  If
    // no arguments are passed in, it will simply return the current
    // global language object.
    numeral.languageData = function(key) {
        if (!key) {
            return languages[options.currentLanguage];
        }

        if (!languages[key]) {
            throw new Error('Unknown language : ' + key);
        }

        return languages[key];
    };

    numeral.language('en', {
        delimiters: {
            thousands: ',',
            decimal: '.'
        },
        abbreviations: {
            thousand: 'k',
            million: 'm',
            billion: 'b',
            trillion: 't'
        },
        ordinal: function(number) {
            var b = number % 10;
            return (~~(number % 100 / 10) === 1) ? 'th' :
                (b === 1) ? 'st' :
                (b === 2) ? 'nd' :
                (b === 3) ? 'rd' : 'th';
        },
        currency: {
            symbol: '$'
        }
    });

    numeral.zeroFormat = function(format) {
        options.zeroFormat = typeof(format) === 'string' ? format : null;
    };

    numeral.nullFormat = function (format) {
        options.nullFormat = typeof(format) === 'string' ? format : null;
    };

    numeral.defaultFormat = function(format) {
        options.defaultFormat = typeof(format) === 'string' ? format : '0.0';
    };

    numeral.validate = function(val, culture) {
        var _decimalSep,
            _thousandSep,
            _currSymbol,
            _valArray,
            _abbrObj,
            _thousandRegEx,
            languageData,
            temp;

        //coerce val to string
        if (typeof val !== 'string') {
            val += '';
            if (console.warn) {
                console.warn('Numeral.js: Value is not string. It has been co-erced to: ', val);
            }
        }

        //trim whitespaces from either sides
        val = val.trim();

        //if val is just digits return true
        if ( !! val.match(/^\d+$/)) {
            return true;
        }

        //if val is empty return false
        if (val === '') {
            return false;
        }

        //get the decimal and thousands separator from numeral.languageData
        try {
            //check if the culture is understood by numeral. if not, default it to current language
            languageData = numeral.languageData(culture);
        } catch (e) {
            languageData = numeral.languageData(numeral.language());
        }

        //setup the delimiters and currency symbol based on culture/language
        _currSymbol = languageData.currency.symbol;
        _abbrObj = languageData.abbreviations;
        _decimalSep = languageData.delimiters.decimal;
        if (languageData.delimiters.thousands === '.') {
            _thousandSep = '\\.';
        } else {
            _thousandSep = languageData.delimiters.thousands;
        }

        // validating currency symbol
        temp = val.match(/^[^\d]+/);
        if (temp !== null) {
            val = val.substr(1);
            if (temp[0] !== _currSymbol) {
                return false;
            }
        }

        //validating abbreviation symbol
        temp = val.match(/[^\d]+$/);
        if (temp !== null) {
            val = val.slice(0, -1);
            if (temp[0] !== _abbrObj.thousand && temp[0] !== _abbrObj.million && temp[0] !== _abbrObj.billion && temp[0] !== _abbrObj.trillion) {
                return false;
            }
        }

        _thousandRegEx = new RegExp(_thousandSep + '{2}');

        if (!val.match(/[^\d.,]/g)) {
            _valArray = val.split(_decimalSep);
            if (_valArray.length > 2) {
                return false;
            } else {
                if (_valArray.length < 2) {
                    return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx));
                } else {
                    if (_valArray[0].length === 1) {
                        return ( !! _valArray[0].match(/^\d+$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/));
                    } else {
                        return ( !! _valArray[0].match(/^\d+.*\d$/) && !_valArray[0].match(_thousandRegEx) && !! _valArray[1].match(/^\d+$/));
                    }
                }
            }
        }

        return false;
    };

    /************************************
        Helpers
    ************************************/

    function loadLanguage(key, values) {
        languages[key] = values;
    }

    /************************************
        Floating-point helpers
    ************************************/

    // The floating-point helper functions and implementation
    // borrows heavily from sinful.js: http://guipn.github.io/sinful.js/

    // Production steps of ECMA-262, Edition 5, 15.4.4.21
    // Reference: http://es5.github.io/#x15.4.4.21
    if (!Array.prototype.reduce) {
        Array.prototype.reduce = function(callback /*, initialValue*/) {
            'use strict';
            if (this === null) {
                throw new TypeError('Array.prototype.reduce called on null or undefined');
            }

            if (typeof callback !== 'function') {
                throw new TypeError(callback + ' is not a function');
            }

            var t = Object(this), len = t.length >>> 0, k = 0, value;

            if (arguments.length === 2) {
                value = arguments[1];
            } else {
                while (k < len && !(k in t)) {
                    k++;
                }

                if (k >= len) {
                    throw new TypeError('Reduce of empty array with no initial value');
                }

                value = t[k++];
            }
            for (; k < len; k++) {
                if (k in t) {
                    value = callback(value, t[k], k, t);
                }
            }
            return value;
        };
    }

    /**
     * Computes the multiplier necessary to make x >= 1,
     * effectively eliminating miscalculations caused by
     * finite precision.
     */
    function multiplier(x) {
        var parts = x.toString().split('.');
        if (parts.length < 2) {
            return 1;
        }
        return Math.pow(10, parts[1].length);
    }

    /**
     * Given a variable number of arguments, returns the maximum
     * multiplier that must be used to normalize an operation involving
     * all of them.
     */
    function correctionFactor() {
        var args = Array.prototype.slice.call(arguments);
        return args.reduce(function(prev, next) {
            var mp = multiplier(prev),
                mn = multiplier(next);
            return mp > mn ? mp : mn;
        }, -Infinity);
    }


    /************************************
        Numeral Prototype
    ************************************/


    numeral.fn = Numeral.prototype = {

        clone: function() {
            return numeral(this);
        },

        format: function (inputString, roundingFunction) {
            return formatNumeral(this,
                inputString ? inputString : options.defaultFormat,
                roundingFunction !== undefined ? roundingFunction : Math.round
            );
        },

        unformat: function (inputString) {
            if (Object.prototype.toString.call(inputString) === '[object Number]') {
                return inputString;
            }

            return unformatNumeral(this, inputString ? inputString : options.defaultFormat);
        },

        value: function() {
            return this._value;
        },

        valueOf: function() {
            return this._value;
        },

        set: function(value) {
            this._value = Number(value);
            return this;
        },

        add: function(value) {
            var corrFactor = correctionFactor.call(null, this._value, value);

            function cback(accum, curr, currI, O) {
                return accum + corrFactor * curr;
            }
            this._value = [this._value, value].reduce(cback, 0) / corrFactor;
            return this;
        },

        subtract: function(value) {
            var corrFactor = correctionFactor.call(null, this._value, value);

            function cback(accum, curr, currI, O) {
                return accum - corrFactor * curr;
            }
            this._value = [value].reduce(cback, this._value * corrFactor) / corrFactor;
            return this;
        },

        multiply: function(value) {
            function cback(accum, curr, currI, O) {
                var corrFactor = correctionFactor(accum, curr);
                return (accum * corrFactor) * (curr * corrFactor) /
                    (corrFactor * corrFactor);
            }
            this._value = [this._value, value].reduce(cback, 1);
            return this;
        },

        divide: function(value) {
            function cback(accum, curr, currI, O) {
                var corrFactor = correctionFactor(accum, curr);
                return (accum * corrFactor) / (curr * corrFactor);
            }
            this._value = [this._value, value].reduce(cback);
            return this;
        },

        difference: function(value) {
            return Math.abs(numeral(this._value).subtract(value).value());
        }

    };

    /************************************
        Exposing Numeral
    ************************************/

    // CommonJS module is defined
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = numeral;
    }

    /*global ender:false */
    if (typeof ender === 'undefined') {
        // here, `this` means `window` in the browser, or `global` on the server
        // add `numeral` as a global object via a string identifier,
        // for Closure Compiler 'advanced' mode
        this['numeral'] = numeral;
    }

    /*global define:false */
    if (typeof define === 'function' && define.amd) {
        define([], function() {
            return numeral;
        });
    }
}).call(this);

},{}],221:[function(require,module,exports){
/**
 * Outlayer Item
 */

( function( window, factory ) {
  // universal module definition
  /* jshint strict: false */ /* globals define, module, require */
  if ( typeof define == 'function' && define.amd ) {
    // AMD - RequireJS
    define( [
        'ev-emitter/ev-emitter',
        'get-size/get-size'
      ],
      factory
    );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS - Browserify, Webpack
    module.exports = factory(
      require('ev-emitter'),
      require('get-size')
    );
  } else {
    // browser global
    window.Outlayer = {};
    window.Outlayer.Item = factory(
      window.EvEmitter,
      window.getSize
    );
  }

}( window, function factory( EvEmitter, getSize ) {
'use strict';

// ----- helpers ----- //

function isEmptyObj( obj ) {
  for ( var prop in obj ) {
    return false;
  }
  prop = null;
  return true;
}

// -------------------------- CSS3 support -------------------------- //


var docElemStyle = document.documentElement.style;

var transitionProperty = typeof docElemStyle.transition == 'string' ?
  'transition' : 'WebkitTransition';
var transformProperty = typeof docElemStyle.transform == 'string' ?
  'transform' : 'WebkitTransform';

var transitionEndEvent = {
  WebkitTransition: 'webkitTransitionEnd',
  transition: 'transitionend'
}[ transitionProperty ];

// cache all vendor properties that could have vendor prefix
var vendorProperties = {
  transform: transformProperty,
  transition: transitionProperty,
  transitionDuration: transitionProperty + 'Duration',
  transitionProperty: transitionProperty + 'Property',
  transitionDelay: transitionProperty + 'Delay'
};

// -------------------------- Item -------------------------- //

function Item( element, layout ) {
  if ( !element ) {
    return;
  }

  this.element = element;
  // parent layout class, i.e. Masonry, Isotope, or Packery
  this.layout = layout;
  this.position = {
    x: 0,
    y: 0
  };

  this._create();
}

// inherit EvEmitter
var proto = Item.prototype = Object.create( EvEmitter.prototype );
proto.constructor = Item;

proto._create = function() {
  // transition objects
  this._transn = {
    ingProperties: {},
    clean: {},
    onEnd: {}
  };

  this.css({
    position: 'absolute'
  });
};

// trigger specified handler for event type
proto.handleEvent = function( event ) {
  var method = 'on' + event.type;
  if ( this[ method ] ) {
    this[ method ]( event );
  }
};

proto.getSize = function() {
  this.size = getSize( this.element );
};

/**
 * apply CSS styles to element
 * @param {Object} style
 */
proto.css = function( style ) {
  var elemStyle = this.element.style;

  for ( var prop in style ) {
    // use vendor property if available
    var supportedProp = vendorProperties[ prop ] || prop;
    elemStyle[ supportedProp ] = style[ prop ];
  }
};

 // measure position, and sets it
proto.getPosition = function() {
  var style = getComputedStyle( this.element );
  var isOriginLeft = this.layout._getOption('originLeft');
  var isOriginTop = this.layout._getOption('originTop');
  var xValue = style[ isOriginLeft ? 'left' : 'right' ];
  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
  var x = parseFloat( xValue );
  var y = parseFloat( yValue );
  // convert percent to pixels
  var layoutSize = this.layout.size;
  if ( xValue.indexOf('%') != -1 ) {
    x = ( x / 100 ) * layoutSize.width;
  }
  if ( yValue.indexOf('%') != -1 ) {
    y = ( y / 100 ) * layoutSize.height;
  }
  // clean up 'auto' or other non-integer values
  x = isNaN( x ) ? 0 : x;
  y = isNaN( y ) ? 0 : y;
  // remove padding from measurement
  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;

  this.position.x = x;
  this.position.y = y;
};

// set settled position, apply padding
proto.layoutPosition = function() {
  var layoutSize = this.layout.size;
  var style = {};
  var isOriginLeft = this.layout._getOption('originLeft');
  var isOriginTop = this.layout._getOption('originTop');

  // x
  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
  var xProperty = isOriginLeft ? 'left' : 'right';
  var xResetProperty = isOriginLeft ? 'right' : 'left';

  var x = this.position.x + layoutSize[ xPadding ];
  // set in percentage or pixels
  style[ xProperty ] = this.getXValue( x );
  // reset other property
  style[ xResetProperty ] = '';

  // y
  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
  var yProperty = isOriginTop ? 'top' : 'bottom';
  var yResetProperty = isOriginTop ? 'bottom' : 'top';

  var y = this.position.y + layoutSize[ yPadding ];
  // set in percentage or pixels
  style[ yProperty ] = this.getYValue( y );
  // reset other property
  style[ yResetProperty ] = '';

  this.css( style );
  this.emitEvent( 'layout', [ this ] );
};

proto.getXValue = function( x ) {
  var isHorizontal = this.layout._getOption('horizontal');
  return this.layout.options.percentPosition && !isHorizontal ?
    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
};

proto.getYValue = function( y ) {
  var isHorizontal = this.layout._getOption('horizontal');
  return this.layout.options.percentPosition && isHorizontal ?
    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
};

proto._transitionTo = function( x, y ) {
  this.getPosition();
  // get current x & y from top/left
  var curX = this.position.x;
  var curY = this.position.y;

  var didNotMove = x == this.position.x && y == this.position.y;

  // save end position
  this.setPosition( x, y );

  // if did not move and not transitioning, just go to layout
  if ( didNotMove && !this.isTransitioning ) {
    this.layoutPosition();
    return;
  }

  var transX = x - curX;
  var transY = y - curY;
  var transitionStyle = {};
  transitionStyle.transform = this.getTranslate( transX, transY );

  this.transition({
    to: transitionStyle,
    onTransitionEnd: {
      transform: this.layoutPosition
    },
    isCleaning: true
  });
};

proto.getTranslate = function( x, y ) {
  // flip cooridinates if origin on right or bottom
  var isOriginLeft = this.layout._getOption('originLeft');
  var isOriginTop = this.layout._getOption('originTop');
  x = isOriginLeft ? x : -x;
  y = isOriginTop ? y : -y;
  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
};

// non transition + transform support
proto.goTo = function( x, y ) {
  this.setPosition( x, y );
  this.layoutPosition();
};

proto.moveTo = proto._transitionTo;

proto.setPosition = function( x, y ) {
  this.position.x = parseFloat( x );
  this.position.y = parseFloat( y );
};

// ----- transition ----- //

/**
 * @param {Object} style - CSS
 * @param {Function} onTransitionEnd
 */

// non transition, just trigger callback
proto._nonTransition = function( args ) {
  this.css( args.to );
  if ( args.isCleaning ) {
    this._removeStyles( args.to );
  }
  for ( var prop in args.onTransitionEnd ) {
    args.onTransitionEnd[ prop ].call( this );
  }
};

/**
 * proper transition
 * @param {Object} args - arguments
 *   @param {Object} to - style to transition to
 *   @param {Object} from - style to start transition from
 *   @param {Boolean} isCleaning - removes transition styles after transition
 *   @param {Function} onTransitionEnd - callback
 */
proto.transition = function( args ) {
  // redirect to nonTransition if no transition duration
  if ( !parseFloat( this.layout.options.transitionDuration ) ) {
    this._nonTransition( args );
    return;
  }

  var _transition = this._transn;
  // keep track of onTransitionEnd callback by css property
  for ( var prop in args.onTransitionEnd ) {
    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
  }
  // keep track of properties that are transitioning
  for ( prop in args.to ) {
    _transition.ingProperties[ prop ] = true;
    // keep track of properties to clean up when transition is done
    if ( args.isCleaning ) {
      _transition.clean[ prop ] = true;
    }
  }

  // set from styles
  if ( args.from ) {
    this.css( args.from );
    // force redraw. http://blog.alexmaccaw.com/css-transitions
    var h = this.element.offsetHeight;
    // hack for JSHint to hush about unused var
    h = null;
  }
  // enable transition
  this.enableTransition( args.to );
  // set styles that are transitioning
  this.css( args.to );

  this.isTransitioning = true;

};

// dash before all cap letters, including first for
// WebkitTransform => -webkit-transform
function toDashedAll( str ) {
  return str.replace( /([A-Z])/g, function( $1 ) {
    return '-' + $1.toLowerCase();
  });
}

var transitionProps = 'opacity,' + toDashedAll( transformProperty );

proto.enableTransition = function(/* style */) {
  // HACK changing transitionProperty during a transition
  // will cause transition to jump
  if ( this.isTransitioning ) {
    return;
  }

  // make `transition: foo, bar, baz` from style object
  // HACK un-comment this when enableTransition can work
  // while a transition is happening
  // var transitionValues = [];
  // for ( var prop in style ) {
  //   // dash-ify camelCased properties like WebkitTransition
  //   prop = vendorProperties[ prop ] || prop;
  //   transitionValues.push( toDashedAll( prop ) );
  // }
  // munge number to millisecond, to match stagger
  var duration = this.layout.options.transitionDuration;
  duration = typeof duration == 'number' ? duration + 'ms' : duration;
  // enable transition styles
  this.css({
    transitionProperty: transitionProps,
    transitionDuration: duration,
    transitionDelay: this.staggerDelay || 0
  });
  // listen for transition end event
  this.element.addEventListener( transitionEndEvent, this, false );
};

// ----- events ----- //

proto.onwebkitTransitionEnd = function( event ) {
  this.ontransitionend( event );
};

proto.onotransitionend = function( event ) {
  this.ontransitionend( event );
};

// properties that I munge to make my life easier
var dashedVendorProperties = {
  '-webkit-transform': 'transform'
};

proto.ontransitionend = function( event ) {
  // disregard bubbled events from children
  if ( event.target !== this.element ) {
    return;
  }
  var _transition = this._transn;
  // get property name of transitioned property, convert to prefix-free
  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;

  // remove property that has completed transitioning
  delete _transition.ingProperties[ propertyName ];
  // check if any properties are still transitioning
  if ( isEmptyObj( _transition.ingProperties ) ) {
    // all properties have completed transitioning
    this.disableTransition();
  }
  // clean style
  if ( propertyName in _transition.clean ) {
    // clean up style
    this.element.style[ event.propertyName ] = '';
    delete _transition.clean[ propertyName ];
  }
  // trigger onTransitionEnd callback
  if ( propertyName in _transition.onEnd ) {
    var onTransitionEnd = _transition.onEnd[ propertyName ];
    onTransitionEnd.call( this );
    delete _transition.onEnd[ propertyName ];
  }

  this.emitEvent( 'transitionEnd', [ this ] );
};

proto.disableTransition = function() {
  this.removeTransitionStyles();
  this.element.removeEventListener( transitionEndEvent, this, false );
  this.isTransitioning = false;
};

/**
 * removes style property from element
 * @param {Object} style
**/
proto._removeStyles = function( style ) {
  // clean up transition styles
  var cleanStyle = {};
  for ( var prop in style ) {
    cleanStyle[ prop ] = '';
  }
  this.css( cleanStyle );
};

var cleanTransitionStyle = {
  transitionProperty: '',
  transitionDuration: '',
  transitionDelay: ''
};

proto.removeTransitionStyles = function() {
  // remove transition
  this.css( cleanTransitionStyle );
};

// ----- stagger ----- //

proto.stagger = function( delay ) {
  delay = isNaN( delay ) ? 0 : delay;
  this.staggerDelay = delay + 'ms';
};

// ----- show/hide/remove ----- //

// remove element from DOM
proto.removeElem = function() {
  this.element.parentNode.removeChild( this.element );
  // remove display: none
  this.css({ display: '' });
  this.emitEvent( 'remove', [ this ] );
};

proto.remove = function() {
  // just remove element if no transition support or no transition
  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
    this.removeElem();
    return;
  }

  // start transition
  this.once( 'transitionEnd', function() {
    this.removeElem();
  });
  this.hide();
};

proto.reveal = function() {
  delete this.isHidden;
  // remove display: none
  this.css({ display: '' });

  var options = this.layout.options;

  var onTransitionEnd = {};
  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;

  this.transition({
    from: options.hiddenStyle,
    to: options.visibleStyle,
    isCleaning: true,
    onTransitionEnd: onTransitionEnd
  });
};

proto.onRevealTransitionEnd = function() {
  // check if still visible
  // during transition, item may have been hidden
  if ( !this.isHidden ) {
    this.emitEvent('reveal');
  }
};

/**
 * get style property use for hide/reveal transition end
 * @param {String} styleProperty - hiddenStyle/visibleStyle
 * @returns {String}
 */
proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
  var optionStyle = this.layout.options[ styleProperty ];
  // use opacity
  if ( optionStyle.opacity ) {
    return 'opacity';
  }
  // get first property
  for ( var prop in optionStyle ) {
    return prop;
  }
};

proto.hide = function() {
  // set flag
  this.isHidden = true;
  // remove display: none
  this.css({ display: '' });

  var options = this.layout.options;

  var onTransitionEnd = {};
  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;

  this.transition({
    from: options.visibleStyle,
    to: options.hiddenStyle,
    // keep hidden stuff hidden
    isCleaning: true,
    onTransitionEnd: onTransitionEnd
  });
};

proto.onHideTransitionEnd = function() {
  // check if still hidden
  // during transition, item may have been un-hidden
  if ( this.isHidden ) {
    this.css({ display: 'none' });
    this.emitEvent('hide');
  }
};

proto.destroy = function() {
  this.css({
    position: '',
    left: '',
    right: '',
    top: '',
    bottom: '',
    transition: '',
    transform: ''
  });
};

return Item;

}));

},{"ev-emitter":207,"get-size":209}],222:[function(require,module,exports){
/*!
 * Outlayer v2.1.1
 * the brains and guts of a layout library
 * MIT license
 */

( function( window, factory ) {
  'use strict';
  // universal module definition
  /* jshint strict: false */ /* globals define, module, require */
  if ( typeof define == 'function' && define.amd ) {
    // AMD - RequireJS
    define( [
        'ev-emitter/ev-emitter',
        'get-size/get-size',
        'fizzy-ui-utils/utils',
        './item'
      ],
      function( EvEmitter, getSize, utils, Item ) {
        return factory( window, EvEmitter, getSize, utils, Item);
      }
    );
  } else if ( typeof module == 'object' && module.exports ) {
    // CommonJS - Browserify, Webpack
    module.exports = factory(
      window,
      require('ev-emitter'),
      require('get-size'),
      require('fizzy-ui-utils'),
      require('./item')
    );
  } else {
    // browser global
    window.Outlayer = factory(
      window,
      window.EvEmitter,
      window.getSize,
      window.fizzyUIUtils,
      window.Outlayer.Item
    );
  }

}( window, function factory( window, EvEmitter, getSize, utils, Item ) {
'use strict';

// ----- vars ----- //

var console = window.console;
var jQuery = window.jQuery;
var noop = function() {};

// -------------------------- Outlayer -------------------------- //

// globally unique identifiers
var GUID = 0;
// internal store of all Outlayer intances
var instances = {};


/**
 * @param {Element, String} element
 * @param {Object} options
 * @constructor
 */
function Outlayer( element, options ) {
  var queryElement = utils.getQueryElement( element );
  if ( !queryElement ) {
    if ( console ) {
      console.error( 'Bad element for ' + this.constructor.namespace +
        ': ' + ( queryElement || element ) );
    }
    return;
  }
  this.element = queryElement;
  // add jQuery
  if ( jQuery ) {
    this.$element = jQuery( this.element );
  }

  // options
  this.options = utils.extend( {}, this.constructor.defaults );
  this.option( options );

  // add id for Outlayer.getFromElement
  var id = ++GUID;
  this.element.outlayerGUID = id; // expando
  instances[ id ] = this; // associate via id

  // kick it off
  this._create();

  var isInitLayout = this._getOption('initLayout');
  if ( isInitLayout ) {
    this.layout();
  }
}

// settings are for internal use only
Outlayer.namespace = 'outlayer';
Outlayer.Item = Item;

// default options
Outlayer.defaults = {
  containerStyle: {
    position: 'relative'
  },
  initLayout: true,
  originLeft: true,
  originTop: true,
  resize: true,
  resizeContainer: true,
  // item options
  transitionDuration: '0.4s',
  hiddenStyle: {
    opacity: 0,
    transform: 'scale(0.001)'
  },
  visibleStyle: {
    opacity: 1,
    transform: 'scale(1)'
  }
};

var proto = Outlayer.prototype;
// inherit EvEmitter
utils.extend( proto, EvEmitter.prototype );

/**
 * set options
 * @param {Object} opts
 */
proto.option = function( opts ) {
  utils.extend( this.options, opts );
};

/**
 * get backwards compatible option value, check old name
 */
proto._getOption = function( option ) {
  var oldOption = this.constructor.compatOptions[ option ];
  return oldOption && this.options[ oldOption ] !== undefined ?
    this.options[ oldOption ] : this.options[ option ];
};

Outlayer.compatOptions = {
  // currentName: oldName
  initLayout: 'isInitLayout',
  horizontal: 'isHorizontal',
  layoutInstant: 'isLayoutInstant',
  originLeft: 'isOriginLeft',
  originTop: 'isOriginTop',
  resize: 'isResizeBound',
  resizeContainer: 'isResizingContainer'
};

proto._create = function() {
  // get items from children
  this.reloadItems();
  // elements that affect layout, but are not laid out
  this.stamps = [];
  this.stamp( this.options.stamp );
  // set container style
  utils.extend( this.element.style, this.options.containerStyle );

  // bind resize method
  var canBindResize = this._getOption('resize');
  if ( canBindResize ) {
    this.bindResize();
  }
};

// goes through all children again and gets bricks in proper order
proto.reloadItems = function() {
  // collection of item elements
  this.items = this._itemize( this.element.children );
};


/**
 * turn elements into Outlayer.Items to be used in layout
 * @param {Array or NodeList or HTMLElement} elems
 * @returns {Array} items - collection of new Outlayer Items
 */
proto._itemize = function( elems ) {

  var itemElems = this._filterFindItemElements( elems );
  var Item = this.constructor.Item;

  // create new Outlayer Items for collection
  var items = [];
  for ( var i=0; i < itemElems.length; i++ ) {
    var elem = itemElems[i];
    var item = new Item( elem, this );
    items.push( item );
  }

  return items;
};

/**
 * get item elements to be used in layout
 * @param {Array or NodeList or HTMLElement} elems
 * @returns {Array} items - item elements
 */
proto._filterFindItemElements = function( elems ) {
  return utils.filterFindElements( elems, this.options.itemSelector );
};

/**
 * getter method for getting item elements
 * @returns {Array} elems - collection of item elements
 */
proto.getItemElements = function() {
  return this.items.map( function( item ) {
    return item.element;
  });
};

// ----- init & layout ----- //

/**
 * lays out all items
 */
proto.layout = function() {
  this._resetLayout();
  this._manageStamps();

  // don't animate first layout
  var layoutInstant = this._getOption('layoutInstant');
  var isInstant = layoutInstant !== undefined ?
    layoutInstant : !this._isLayoutInited;
  this.layoutItems( this.items, isInstant );

  // flag for initalized
  this._isLayoutInited = true;
};

// _init is alias for layout
proto._init = proto.layout;

/**
 * logic before any new layout
 */
proto._resetLayout = function() {
  this.getSize();
};


proto.getSize = function() {
  this.size = getSize( this.element );
};

/**
 * get measurement from option, for columnWidth, rowHeight, gutter
 * if option is String -> get element from selector string, & get size of element
 * if option is Element -> get size of element
 * else use option as a number
 *
 * @param {String} measurement
 * @param {String} size - width or height
 * @private
 */
proto._getMeasurement = function( measurement, size ) {
  var option = this.options[ measurement ];
  var elem;
  if ( !option ) {
    // default to 0
    this[ measurement ] = 0;
  } else {
    // use option as an element
    if ( typeof option == 'string' ) {
      elem = this.element.querySelector( option );
    } else if ( option instanceof HTMLElement ) {
      elem = option;
    }
    // use size of element, if element
    this[ measurement ] = elem ? getSize( elem )[ size ] : option;
  }
};

/**
 * layout a collection of item elements
 * @api public
 */
proto.layoutItems = function( items, isInstant ) {
  items = this._getItemsForLayout( items );

  this._layoutItems( items, isInstant );

  this._postLayout();
};

/**
 * get the items to be laid out
 * you may want to skip over some items
 * @param {Array} items
 * @returns {Array} items
 */
proto._getItemsForLayout = function( items ) {
  return items.filter( function( item ) {
    return !item.isIgnored;
  });
};

/**
 * layout items
 * @param {Array} items
 * @param {Boolean} isInstant
 */
proto._layoutItems = function( items, isInstant ) {
  this._emitCompleteOnItems( 'layout', items );

  if ( !items || !items.length ) {
    // no items, emit event with empty array
    return;
  }

  var queue = [];

  items.forEach( function( item ) {
    // get x/y object from method
    var position = this._getItemLayoutPosition( item );
    // enqueue
    position.item = item;
    position.isInstant = isInstant || item.isLayoutInstant;
    queue.push( position );
  }, this );

  this._processLayoutQueue( queue );
};

/**
 * get item layout position
 * @param {Outlayer.Item} item
 * @returns {Object} x and y position
 */
proto._getItemLayoutPosition = function( /* item */ ) {
  return {
    x: 0,
    y: 0
  };
};

/**
 * iterate over array and position each item
 * Reason being - separating this logic prevents 'layout invalidation'
 * thx @paul_irish
 * @param {Array} queue
 */
proto._processLayoutQueue = function( queue ) {
  this.updateStagger();
  queue.forEach( function( obj, i ) {
    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
  }, this );
};

// set stagger from option in milliseconds number
proto.updateStagger = function() {
  var stagger = this.options.stagger;
  if ( stagger === null || stagger === undefined ) {
    this.stagger = 0;
    return;
  }
  this.stagger = getMilliseconds( stagger );
  return this.stagger;
};

/**
 * Sets position of item in DOM
 * @param {Outlayer.Item} item
 * @param {Number} x - horizontal position
 * @param {Number} y - vertical position
 * @param {Boolean} isInstant - disables transitions
 */
proto._positionItem = function( item, x, y, isInstant, i ) {
  if ( isInstant ) {
    // if not transition, just set CSS
    item.goTo( x, y );
  } else {
    item.stagger( i * this.stagger );
    item.moveTo( x, y );
  }
};

/**
 * Any logic you want to do after each layout,
 * i.e. size the container
 */
proto._postLayout = function() {
  this.resizeContainer();
};

proto.resizeContainer = function() {
  var isResizingContainer = this._getOption('resizeContainer');
  if ( !isResizingContainer ) {
    return;
  }
  var size = this._getContainerSize();
  if ( size ) {
    this._setContainerMeasure( size.width, true );
    this._setContainerMeasure( size.height, false );
  }
};

/**
 * Sets width or height of container if returned
 * @returns {Object} size
 *   @param {Number} width
 *   @param {Number} height
 */
proto._getContainerSize = noop;

/**
 * @param {Number} measure - size of width or height
 * @param {Boolean} isWidth
 */
proto._setContainerMeasure = function( measure, isWidth ) {
  if ( measure === undefined ) {
    return;
  }

  var elemSize = this.size;
  // add padding and border width if border box
  if ( elemSize.isBorderBox ) {
    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
      elemSize.borderLeftWidth + elemSize.borderRightWidth :
      elemSize.paddingBottom + elemSize.paddingTop +
      elemSize.borderTopWidth + elemSize.borderBottomWidth;
  }

  measure = Math.max( measure, 0 );
  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
};

/**
 * emit eventComplete on a collection of items events
 * @param {String} eventName
 * @param {Array} items - Outlayer.Items
 */
proto._emitCompleteOnItems = function( eventName, items ) {
  var _this = this;
  function onComplete() {
    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
  }

  var count = items.length;
  if ( !items || !count ) {
    onComplete();
    return;
  }

  var doneCount = 0;
  function tick() {
    doneCount++;
    if ( doneCount == count ) {
      onComplete();
    }
  }

  // bind callback
  items.forEach( function( item ) {
    item.once( eventName, tick );
  });
};

/**
 * emits events via EvEmitter and jQuery events
 * @param {String} type - name of event
 * @param {Event} event - original event
 * @param {Array} args - extra arguments
 */
proto.dispatchEvent = function( type, event, args ) {
  // add original event to arguments
  var emitArgs = event ? [ event ].concat( args ) : args;
  this.emitEvent( type, emitArgs );

  if ( jQuery ) {
    // set this.$element
    this.$element = this.$element || jQuery( this.element );
    if ( event ) {
      // create jQuery event
      var $event = jQuery.Event( event );
      $event.type = type;
      this.$element.trigger( $event, args );
    } else {
      // just trigger with type if no event available
      this.$element.trigger( type, args );
    }
  }
};

// -------------------------- ignore & stamps -------------------------- //


/**
 * keep item in collection, but do not lay it out
 * ignored items do not get skipped in layout
 * @param {Element} elem
 */
proto.ignore = function( elem ) {
  var item = this.getItem( elem );
  if ( item ) {
    item.isIgnored = true;
  }
};

/**
 * return item to layout collection
 * @param {Element} elem
 */
proto.unignore = function( elem ) {
  var item = this.getItem( elem );
  if ( item ) {
    delete item.isIgnored;
  }
};

/**
 * adds elements to stamps
 * @param {NodeList, Array, Element, or String} elems
 */
proto.stamp = function( elems ) {
  elems = this._find( elems );
  if ( !elems ) {
    return;
  }

  this.stamps = this.stamps.concat( elems );
  // ignore
  elems.forEach( this.ignore, this );
};

/**
 * removes elements to stamps
 * @param {NodeList, Array, or Element} elems
 */
proto.unstamp = function( elems ) {
  elems = this._find( elems );
  if ( !elems ){
    return;
  }

  elems.forEach( function( elem ) {
    // filter out removed stamp elements
    utils.removeFrom( this.stamps, elem );
    this.unignore( elem );
  }, this );
};

/**
 * finds child elements
 * @param {NodeList, Array, Element, or String} elems
 * @returns {Array} elems
 */
proto._find = function( elems ) {
  if ( !elems ) {
    return;
  }
  // if string, use argument as selector string
  if ( typeof elems == 'string' ) {
    elems = this.element.querySelectorAll( elems );
  }
  elems = utils.makeArray( elems );
  return elems;
};

proto._manageStamps = function() {
  if ( !this.stamps || !this.stamps.length ) {
    return;
  }

  this._getBoundingRect();

  this.stamps.forEach( this._manageStamp, this );
};

// update boundingLeft / Top
proto._getBoundingRect = function() {
  // get bounding rect for container element
  var boundingRect = this.element.getBoundingClientRect();
  var size = this.size;
  this._boundingRect = {
    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
    top: boundingRect.top + size.paddingTop + size.borderTopWidth,
    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
  };
};

/**
 * @param {Element} stamp
**/
proto._manageStamp = noop;

/**
 * get x/y position of element relative to container element
 * @param {Element} elem
 * @returns {Object} offset - has left, top, right, bottom
 */
proto._getElementOffset = function( elem ) {
  var boundingRect = elem.getBoundingClientRect();
  var thisRect = this._boundingRect;
  var size = getSize( elem );
  var offset = {
    left: boundingRect.left - thisRect.left - size.marginLeft,
    top: boundingRect.top - thisRect.top - size.marginTop,
    right: thisRect.right - boundingRect.right - size.marginRight,
    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
  };
  return offset;
};

// -------------------------- resize -------------------------- //

// enable event handlers for listeners
// i.e. resize -> onresize
proto.handleEvent = utils.handleEvent;

/**
 * Bind layout to window resizing
 */
proto.bindResize = function() {
  window.addEventListener( 'resize', this );
  this.isResizeBound = true;
};

/**
 * Unbind layout to window resizing
 */
proto.unbindResize = function() {
  window.removeEventListener( 'resize', this );
  this.isResizeBound = false;
};

proto.onresize = function() {
  this.resize();
};

utils.debounceMethod( Outlayer, 'onresize', 100 );

proto.resize = function() {
  // don't trigger if size did not change
  // or if resize was unbound. See #9
  if ( !this.isResizeBound || !this.needsResizeLayout() ) {
    return;
  }

  this.layout();
};

/**
 * check if layout is needed post layout
 * @returns Boolean
 */
proto.needsResizeLayout = function() {
  var size = getSize( this.element );
  // check that this.size and size are there
  // IE8 triggers resize on body size change, so they might not be
  var hasSizes = this.size && size;
  return hasSizes && size.innerWidth !== this.size.innerWidth;
};

// -------------------------- methods -------------------------- //

/**
 * add items to Outlayer instance
 * @param {Array or NodeList or Element} elems
 * @returns {Array} items - Outlayer.Items
**/
proto.addItems = function( elems ) {
  var items = this._itemize( elems );
  // add items to collection
  if ( items.length ) {
    this.items = this.items.concat( items );
  }
  return items;
};

/**
 * Layout newly-appended item elements
 * @param {Array or NodeList or Element} elems
 */
proto.appended = function( elems ) {
  var items = this.addItems( elems );
  if ( !items.length ) {
    return;
  }
  // layout and reveal just the new items
  this.layoutItems( items, true );
  this.reveal( items );
};

/**
 * Layout prepended elements
 * @param {Array or NodeList or Element} elems
 */
proto.prepended = function( elems ) {
  var items = this._itemize( elems );
  if ( !items.length ) {
    return;
  }
  // add items to beginning of collection
  var previousItems = this.items.slice(0);
  this.items = items.concat( previousItems );
  // start new layout
  this._resetLayout();
  this._manageStamps();
  // layout new stuff without transition
  this.layoutItems( items, true );
  this.reveal( items );
  // layout previous items
  this.layoutItems( previousItems );
};

/**
 * reveal a collection of items
 * @param {Array of Outlayer.Items} items
 */
proto.reveal = function( items ) {
  this._emitCompleteOnItems( 'reveal', items );
  if ( !items || !items.length ) {
    return;
  }
  var stagger = this.updateStagger();
  items.forEach( function( item, i ) {
    item.stagger( i * stagger );
    item.reveal();
  });
};

/**
 * hide a collection of items
 * @param {Array of Outlayer.Items} items
 */
proto.hide = function( items ) {
  this._emitCompleteOnItems( 'hide', items );
  if ( !items || !items.length ) {
    return;
  }
  var stagger = this.updateStagger();
  items.forEach( function( item, i ) {
    item.stagger( i * stagger );
    item.hide();
  });
};

/**
 * reveal item elements
 * @param {Array}, {Element}, {NodeList} items
 */
proto.revealItemElements = function( elems ) {
  var items = this.getItems( elems );
  this.reveal( items );
};

/**
 * hide item elements
 * @param {Array}, {Element}, {NodeList} items
 */
proto.hideItemElements = function( elems ) {
  var items = this.getItems( elems );
  this.hide( items );
};

/**
 * get Outlayer.Item, given an Element
 * @param {Element} elem
 * @param {Function} callback
 * @returns {Outlayer.Item} item
 */
proto.getItem = function( elem ) {
  // loop through items to get the one that matches
  for ( var i=0; i < this.items.length; i++ ) {
    var item = this.items[i];
    if ( item.element == elem ) {
      // return item
      return item;
    }
  }
};

/**
 * get collection of Outlayer.Items, given Elements
 * @param {Array} elems
 * @returns {Array} items - Outlayer.Items
 */
proto.getItems = function( elems ) {
  elems = utils.makeArray( elems );
  var items = [];
  elems.forEach( function( elem ) {
    var item = this.getItem( elem );
    if ( item ) {
      items.push( item );
    }
  }, this );

  return items;
};

/**
 * remove element(s) from instance and DOM
 * @param {Array or NodeList or Element} elems
 */
proto.remove = function( elems ) {
  var removeItems = this.getItems( elems );

  this._emitCompleteOnItems( 'remove', removeItems );

  // bail if no items to remove
  if ( !removeItems || !removeItems.length ) {
    return;
  }

  removeItems.forEach( function( item ) {
    item.remove();
    // remove item from collection
    utils.removeFrom( this.items, item );
  }, this );
};

// ----- destroy ----- //

// remove and disable Outlayer instance
proto.destroy = function() {
  // clean up dynamic styles
  var style = this.element.style;
  style.height = '';
  style.position = '';
  style.width = '';
  // destroy items
  this.items.forEach( function( item ) {
    item.destroy();
  });

  this.unbindResize();

  var id = this.element.outlayerGUID;
  delete instances[ id ]; // remove reference to instance by id
  delete this.element.outlayerGUID;
  // remove data for jQuery
  if ( jQuery ) {
    jQuery.removeData( this.element, this.constructor.namespace );
  }

};

// -------------------------- data -------------------------- //

/**
 * get Outlayer instance from element
 * @param {Element} elem
 * @returns {Outlayer}
 */
Outlayer.data = function( elem ) {
  elem = utils.getQueryElement( elem );
  var id = elem && elem.outlayerGUID;
  return id && instances[ id ];
};


// -------------------------- create Outlayer class -------------------------- //

/**
 * create a layout class
 * @param {String} namespace
 */
Outlayer.create = function( namespace, options ) {
  // sub-class Outlayer
  var Layout = subclass( Outlayer );
  // apply new options and compatOptions
  Layout.defaults = utils.extend( {}, Outlayer.defaults );
  utils.extend( Layout.defaults, options );
  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );

  Layout.namespace = namespace;

  Layout.data = Outlayer.data;

  // sub-class Item
  Layout.Item = subclass( Item );

  // -------------------------- declarative -------------------------- //

  utils.htmlInit( Layout, namespace );

  // -------------------------- jQuery bridge -------------------------- //

  // make into jQuery plugin
  if ( jQuery && jQuery.bridget ) {
    jQuery.bridget( namespace, Layout );
  }

  return Layout;
};

function subclass( Parent ) {
  function SubClass() {
    Parent.apply( this, arguments );
  }

  SubClass.prototype = Object.create( Parent.prototype );
  SubClass.prototype.constructor = SubClass;

  return SubClass;
}

// ----- helpers ----- //

// how many milliseconds are in each unit
var msUnits = {
  ms: 1,
  s: 1000
};

// munge time-like parameter into millisecond number
// '0.4s' -> 40
function getMilliseconds( time ) {
  if ( typeof time == 'number' ) {
    return time;
  }
  var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
  var num = matches && matches[1];
  var unit = matches && matches[2];
  if ( !num.length ) {
    return 0;
  }
  num = parseFloat( num );
  var mult = msUnits[ unit ] || 1;
  return num * mult;
}

// ----- fin ----- //

// back in global
Outlayer.Item = Item;

return Outlayer;

}));

},{"./item":221,"ev-emitter":207,"fizzy-ui-utils":208,"get-size":209}],223:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};

// cached from whatever global is present so that test runners that stub it
// don't break things.  But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals.  It's inside a
// function because try/catches deoptimize in certain engines.

var cachedSetTimeout;
var cachedClearTimeout;

function defaultSetTimout() {
    throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
    throw new Error('clearTimeout has not been defined');
}
(function () {
    try {
        if (typeof setTimeout === 'function') {
            cachedSetTimeout = setTimeout;
        } else {
            cachedSetTimeout = defaultSetTimout;
        }
    } catch (e) {
        cachedSetTimeout = defaultSetTimout;
    }
    try {
        if (typeof clearTimeout === 'function') {
            cachedClearTimeout = clearTimeout;
        } else {
            cachedClearTimeout = defaultClearTimeout;
        }
    } catch (e) {
        cachedClearTimeout = defaultClearTimeout;
    }
} ())
function runTimeout(fun) {
    if (cachedSetTimeout === setTimeout) {
        //normal enviroments in sane situations
        return setTimeout(fun, 0);
    }
    // if setTimeout wasn't available but was latter defined
    if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
        cachedSetTimeout = setTimeout;
        return setTimeout(fun, 0);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedSetTimeout(fun, 0);
    } catch(e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
            return cachedSetTimeout.call(null, fun, 0);
        } catch(e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
            return cachedSetTimeout.call(this, fun, 0);
        }
    }


}
function runClearTimeout(marker) {
    if (cachedClearTimeout === clearTimeout) {
        //normal enviroments in sane situations
        return clearTimeout(marker);
    }
    // if clearTimeout wasn't available but was latter defined
    if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
        cachedClearTimeout = clearTimeout;
        return clearTimeout(marker);
    }
    try {
        // when when somebody has screwed with setTimeout but no I.E. maddness
        return cachedClearTimeout(marker);
    } catch (e){
        try {
            // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
            return cachedClearTimeout.call(null, marker);
        } catch (e){
            // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
            // Some versions of I.E. have different rules for clearTimeout vs setTimeout
            return cachedClearTimeout.call(this, marker);
        }
    }



}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;

function cleanUpNextTick() {
    if (!draining || !currentQueue) {
        return;
    }
    draining = false;
    if (currentQueue.length) {
        queue = currentQueue.concat(queue);
    } else {
        queueIndex = -1;
    }
    if (queue.length) {
        drainQueue();
    }
}

function drainQueue() {
    if (draining) {
        return;
    }
    var timeout = runTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
        currentQueue = queue;
        queue = [];
        while (++queueIndex < len) {
            if (currentQueue) {
                currentQueue[queueIndex].run();
            }
        }
        queueIndex = -1;
        len = queue.length;
    }
    currentQueue = null;
    draining = false;
    runClearTimeout(timeout);
}

process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
        for (var i = 1; i < arguments.length; i++) {
            args[i - 1] = arguments[i];
        }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
        runTimeout(drainQueue);
    }
};

// v8 likes predictible objects
function Item(fun, array) {
    this.fun = fun;
    this.array = array;
}
Item.prototype.run = function () {
    this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;

process.listeners = function (name) { return [] }

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };

},{}],224:[function(require,module,exports){
function select(element) {
    var selectedText;

    if (element.nodeName === 'SELECT') {
        element.focus();

        selectedText = element.value;
    }
    else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {
        var isReadOnly = element.hasAttribute('readonly');

        if (!isReadOnly) {
            element.setAttribute('readonly', '');
        }

        element.select();
        element.setSelectionRange(0, element.value.length);

        if (!isReadOnly) {
            element.removeAttribute('readonly');
        }

        selectedText = element.value;
    }
    else {
        if (element.hasAttribute('contenteditable')) {
            element.focus();
        }

        var selection = window.getSelection();
        var range = document.createRange();

        range.selectNodeContents(element);
        selection.removeAllRanges();
        selection.addRange(range);

        selectedText = selection.toString();
    }

    return selectedText;
}

module.exports = select;

},{}],225:[function(require,module,exports){
(function (setImmediate,clearImmediate){
var nextTick = require('process/browser.js').nextTick;
var apply = Function.prototype.apply;
var slice = Array.prototype.slice;
var immediateIds = {};
var nextImmediateId = 0;

// DOM APIs, for completeness

exports.setTimeout = function() {
  return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
};
exports.setInterval = function() {
  return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
};
exports.clearTimeout =
exports.clearInterval = function(timeout) { timeout.close(); };

function Timeout(id, clearFn) {
  this._id = id;
  this._clearFn = clearFn;
}
Timeout.prototype.unref = Timeout.prototype.ref = function() {};
Timeout.prototype.close = function() {
  this._clearFn.call(window, this._id);
};

// Does not start the time, just sets up the members needed.
exports.enroll = function(item, msecs) {
  clearTimeout(item._idleTimeoutId);
  item._idleTimeout = msecs;
};

exports.unenroll = function(item) {
  clearTimeout(item._idleTimeoutId);
  item._idleTimeout = -1;
};

exports._unrefActive = exports.active = function(item) {
  clearTimeout(item._idleTimeoutId);

  var msecs = item._idleTimeout;
  if (msecs >= 0) {
    item._idleTimeoutId = setTimeout(function onTimeout() {
      if (item._onTimeout)
        item._onTimeout();
    }, msecs);
  }
};

// That's not how node.js implements it but the exposed api is the same.
exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) {
  var id = nextImmediateId++;
  var args = arguments.length < 2 ? false : slice.call(arguments, 1);

  immediateIds[id] = true;

  nextTick(function onNextTick() {
    if (immediateIds[id]) {
      // fn.call() is faster so we optimize for the common use-case
      // @see http://jsperf.com/call-apply-segu
      if (args) {
        fn.apply(null, args);
      } else {
        fn.call(null);
      }
      // Prevent ids from leaking
      exports.clearImmediate(id);
    }
  });

  return id;
};

exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) {
  delete immediateIds[id];
};
}).call(this,require("timers").setImmediate,require("timers").clearImmediate)

},{"process/browser.js":223,"timers":225}],226:[function(require,module,exports){
function E () {
  // Keep this empty so it's easier to inherit from
  // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)
}

E.prototype = {
  on: function (name, callback, ctx) {
    var e = this.e || (this.e = {});

    (e[name] || (e[name] = [])).push({
      fn: callback,
      ctx: ctx
    });

    return this;
  },

  once: function (name, callback, ctx) {
    var self = this;
    function listener () {
      self.off(name, listener);
      callback.apply(ctx, arguments);
    };

    listener._ = callback
    return this.on(name, listener, ctx);
  },

  emit: function (name) {
    var data = [].slice.call(arguments, 1);
    var evtArr = ((this.e || (this.e = {}))[name] || []).slice();
    var i = 0;
    var len = evtArr.length;

    for (i; i < len; i++) {
      evtArr[i].fn.apply(evtArr[i].ctx, data);
    }

    return this;
  },

  off: function (name, callback) {
    var e = this.e || (this.e = {});
    var evts = e[name];
    var liveEvents = [];

    if (evts && callback) {
      for (var i = 0, len = evts.length; i < len; i++) {
        if (evts[i].fn !== callback && evts[i].fn._ !== callback)
          liveEvents.push(evts[i]);
      }
    }

    // Remove event from queue to prevent memory leak
    // Suggested by https://github.com/lazd
    // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910

    (liveEvents.length)
      ? e[name] = liveEvents
      : delete e[name];

    return this;
  }
};

module.exports = E;
module.exports.TinyEmitter = E;

},{}],227:[function(require,module,exports){
/*! typograf | © 2024 Denis Seleznev | MIT  License | https://github.com/typograf/typograf */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Typograf = factory());
})(this, (function () { 'use strict';

    /******************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */
    /* global Reflect, Promise, SuppressedError, Symbol */


    var __assign = function() {
        __assign = Object.assign || function __assign(t) {
            for (var s, i = 1, n = arguments.length; i < n; i++) {
                s = arguments[i];
                for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
            }
            return t;
        };
        return __assign.apply(this, arguments);
    };

    function __spreadArray(to, from, pack) {
        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
            if (ar || !(i in from)) {
                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
                ar[i] = from[i];
            }
        }
        return to.concat(ar || Array.prototype.slice.call(from));
    }

    typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
        var e = new Error(message);
        return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
    };

    // http://www.w3.org/TR/html4/sgml/entities
    var visibleEntities = [
        ['iexcl', 161],
        ['cent', 162],
        ['pound', 163],
        ['curren', 164],
        ['yen', 165],
        ['brvbar', 166],
        ['sect', 167],
        ['uml', 168],
        ['copy', 169],
        ['ordf', 170],
        ['laquo', 171],
        ['not', 172],
        ['reg', 174],
        ['macr', 175],
        ['deg', 176],
        ['plusmn', 177],
        ['sup2', 178],
        ['sup3', 179],
        ['acute', 180],
        ['micro', 181],
        ['para', 182],
        ['middot', 183],
        ['cedil', 184],
        ['sup1', 185],
        ['ordm', 186],
        ['raquo', 187],
        ['frac14', 188],
        ['frac12', 189],
        ['frac34', 190],
        ['iquest', 191],
        ['Agrave', 192],
        ['Aacute', 193],
        ['Acirc', 194],
        ['Atilde', 195],
        ['Auml', 196],
        ['Aring', 197],
        ['AElig', 198],
        ['Ccedil', 199],
        ['Egrave', 200],
        ['Eacute', 201],
        ['Ecirc', 202],
        ['Euml', 203],
        ['Igrave', 204],
        ['Iacute', 205],
        ['Icirc', 206],
        ['Iuml', 207],
        ['ETH', 208],
        ['Ntilde', 209],
        ['Ograve', 210],
        ['Oacute', 211],
        ['Ocirc', 212],
        ['Otilde', 213],
        ['Ouml', 214],
        ['times', 215],
        ['Oslash', 216],
        ['Ugrave', 217],
        ['Uacute', 218],
        ['Ucirc', 219],
        ['Uuml', 220],
        ['Yacute', 221],
        ['THORN', 222],
        ['szlig', 223],
        ['agrave', 224],
        ['aacute', 225],
        ['acirc', 226],
        ['atilde', 227],
        ['auml', 228],
        ['aring', 229],
        ['aelig', 230],
        ['ccedil', 231],
        ['egrave', 232],
        ['eacute', 233],
        ['ecirc', 234],
        ['euml', 235],
        ['igrave', 236],
        ['iacute', 237],
        ['icirc', 238],
        ['iuml', 239],
        ['eth', 240],
        ['ntilde', 241],
        ['ograve', 242],
        ['oacute', 243],
        ['ocirc', 244],
        ['otilde', 245],
        ['ouml', 246],
        ['divide', 247],
        ['oslash', 248],
        ['ugrave', 249],
        ['uacute', 250],
        ['ucirc', 251],
        ['uuml', 252],
        ['yacute', 253],
        ['thorn', 254],
        ['yuml', 255],
        ['fnof', 402],
        ['Alpha', 913],
        ['Beta', 914],
        ['Gamma', 915],
        ['Delta', 916],
        ['Epsilon', 917],
        ['Zeta', 918],
        ['Eta', 919],
        ['Theta', 920],
        ['Iota', 921],
        ['Kappa', 922],
        ['Lambda', 923],
        ['Mu', 924],
        ['Nu', 925],
        ['Xi', 926],
        ['Omicron', 927],
        ['Pi', 928],
        ['Rho', 929],
        ['Sigma', 931],
        ['Tau', 932],
        ['Upsilon', 933],
        ['Phi', 934],
        ['Chi', 935],
        ['Psi', 936],
        ['Omega', 937],
        ['alpha', 945],
        ['beta', 946],
        ['gamma', 947],
        ['delta', 948],
        ['epsilon', 949],
        ['zeta', 950],
        ['eta', 951],
        ['theta', 952],
        ['iota', 953],
        ['kappa', 954],
        ['lambda', 955],
        ['mu', 956],
        ['nu', 957],
        ['xi', 958],
        ['omicron', 959],
        ['pi', 960],
        ['rho', 961],
        ['sigmaf', 962],
        ['sigma', 963],
        ['tau', 964],
        ['upsilon', 965],
        ['phi', 966],
        ['chi', 967],
        ['psi', 968],
        ['omega', 969],
        ['thetasym', 977],
        ['upsih', 978],
        ['piv', 982],
        ['bull', 8226],
        ['hellip', 8230],
        ['prime', 8242],
        ['Prime', 8243],
        ['oline', 8254],
        ['frasl', 8260],
        ['weierp', 8472],
        ['image', 8465],
        ['real', 8476],
        ['trade', 8482],
        ['alefsym', 8501],
        ['larr', 8592],
        ['uarr', 8593],
        ['rarr', 8594],
        ['darr', 8595],
        ['harr', 8596],
        ['crarr', 8629],
        ['lArr', 8656],
        ['uArr', 8657],
        ['rArr', 8658],
        ['dArr', 8659],
        ['hArr', 8660],
        ['forall', 8704],
        ['part', 8706],
        ['exist', 8707],
        ['empty', 8709],
        ['nabla', 8711],
        ['isin', 8712],
        ['notin', 8713],
        ['ni', 8715],
        ['prod', 8719],
        ['sum', 8721],
        ['minus', 8722],
        ['lowast', 8727],
        ['radic', 8730],
        ['prop', 8733],
        ['infin', 8734],
        ['ang', 8736],
        ['and', 8743],
        ['or', 8744],
        ['cap', 8745],
        ['cup', 8746],
        ['int', 8747],
        ['there4', 8756],
        ['sim', 8764],
        ['cong', 8773],
        ['asymp', 8776],
        ['ne', 8800],
        ['equiv', 8801],
        ['le', 8804],
        ['ge', 8805],
        ['sub', 8834],
        ['sup', 8835],
        ['nsub', 8836],
        ['sube', 8838],
        ['supe', 8839],
        ['oplus', 8853],
        ['otimes', 8855],
        ['perp', 8869],
        ['sdot', 8901],
        ['lceil', 8968],
        ['rceil', 8969],
        ['lfloor', 8970],
        ['rfloor', 8971],
        ['lang', 9001],
        ['rang', 9002],
        ['spades', 9824],
        ['clubs', 9827],
        ['hearts', 9829],
        ['diams', 9830],
        ['loz', 9674],
        ['OElig', 338],
        ['oelig', 339],
        ['Scaron', 352],
        ['scaron', 353],
        ['Yuml', 376],
        ['circ', 710],
        ['tilde', 732],
        ['ndash', 8211],
        ['mdash', 8212],
        ['lsquo', 8216],
        ['rsquo', 8217],
        ['sbquo', 8218],
        ['ldquo', 8220],
        ['rdquo', 8221],
        ['bdquo', 8222],
        ['dagger', 8224],
        ['Dagger', 8225],
        ['permil', 8240],
        ['lsaquo', 8249],
        ['rsaquo', 8250],
        ['euro', 8364],
        ['NestedGreaterGreater', 8811],
        ['NestedLessLess', 8810]
    ];

    var invisibleEntities = [
        ['nbsp', 160],
        ['thinsp', 8201],
        ['ensp', 8194],
        ['emsp', 8195],
        ['shy', 173],
        ['zwnj', 8204],
        ['zwj', 8205],
        ['lrm', 8206],
        ['rlm', 8207]
    ];

    var HtmlEntities = /** @class */ (function () {
        function HtmlEntities() {
            var _this = this;
            this.entities = this.prepareEntities(__spreadArray(__spreadArray([], visibleEntities, true), invisibleEntities, true));
            this.entitiesByName = {};
            this.entitiesByNameEntity = {};
            this.entitiesByDigitEntity = {};
            this.entitiesByUtf = {};
            this.entities.forEach(function (entity) {
                _this.entitiesByName[entity.name] = entity;
                _this.entitiesByNameEntity[entity.nameEntity] = entity;
                _this.entitiesByDigitEntity[entity.digitEntity] = entity;
                _this.entitiesByUtf[entity.utf] = entity;
            });
            this.invisibleEntities = this.prepareEntities(invisibleEntities);
        }
        /**
         * Entities as name or digit to UTF-8.
         */
        HtmlEntities.prototype.toUtf = function (context) {
            var _this = this;
            if (context.text.search(/&#/) !== -1) {
                context.text = this.decHexToUtf(context.text);
            }
            if (context.text.search(/&[a-z]/i) !== -1) {
                // 2 - min length of entity without & and ;. Example: &DD;
                // 31 - max length of entity without & and ;. Example: &CounterClockwiseContourIntegral;
                context.text = context.text.replace(/&[a-z\d]{2,31};/gi, function (key) {
                    var entity = _this.entitiesByNameEntity[key];
                    return entity ? entity.utf : key;
                });
            }
        };
        /**
         * Entities in decimal or hexadecimal form to UTF-8.
         */
        HtmlEntities.prototype.decHexToUtf = function (text) {
            return text
                .replace(/&#(\d{1,6});/gi, function ($0, $1) {
                return String.fromCharCode(parseInt($1, 10));
            })
                .replace(/&#x([\da-f]{1,6});/gi, function ($0, $1) {
                return String.fromCharCode(parseInt($1, 16));
            });
        };
        /**
         * Restore HTML entities in text.
         */
        HtmlEntities.prototype.restore = function (context) {
            var params = context.prefs.htmlEntity;
            var type = params.type;
            var entities = this.entities;
            if (type === 'name' || type === 'digit') {
                if (params.onlyInvisible || params.list) {
                    entities = [];
                    if (params.onlyInvisible) {
                        entities = entities.concat(this.invisibleEntities);
                    }
                    if (params.list) {
                        entities = entities.concat(this.prepareListParam(params.list));
                    }
                }
                var entityType = type === 'name' ? 'nameEntity' : 'digitEntity';
                context.text = this.restoreEntitiesByIndex(context.text, entityType, entities);
            }
        };
        /**
         * Get a entity by utf using the type.
         */
        HtmlEntities.prototype.getByUtf = function (symbol, type) {
            var result;
            switch (type) {
                case 'digit':
                    result = this.entitiesByDigitEntity[symbol];
                    break;
                case 'name':
                    result = this.entitiesByNameEntity[symbol];
                    break;
                default:
                    result = symbol;
                    break;
            }
            return result;
        };
        HtmlEntities.prototype.prepareEntities = function (entities) {
            var result = [];
            entities.forEach(function (entity) {
                var name = entity[0], digit = entity[1];
                var utf = String.fromCharCode(digit);
                result.push({
                    name: name,
                    nameEntity: '&' + name + ';', // &nbsp;
                    digitEntity: '&#' + digit + ';', // &#160;
                    utf: utf, // \u00A0
                    reName: new RegExp('&' + name + ';', 'g'),
                    reUtf: new RegExp(utf, 'g')
                });
            });
            return result;
        };
        HtmlEntities.prototype.prepareListParam = function (list) {
            var _this = this;
            var result = [];
            list.forEach(function (name) {
                var entity = _this.entitiesByName[name];
                if (entity) {
                    result.push(entity);
                }
            });
            return result;
        };
        HtmlEntities.prototype.restoreEntitiesByIndex = function (text, type, entities) {
            entities.forEach(function (entity) {
                text = text.replace(entity.reUtf, entity[type]);
            });
            return text;
        };
        return HtmlEntities;
    }());
    var htmlEntities = new HtmlEntities();

    var locales = [];
    function addLocale(locale) {
        var code = (locale || '').split('/')[0];
        if (code && code !== 'common' && !hasLocale(code)) {
            locales.push(code);
            locales.sort();
        }
    }
    function getLocales() {
        return locales;
    }
    function hasLocale(locale) {
        return locale === 'common' || locales.indexOf(locale) !== -1;
    }
    function prepareLocale(locale1, locale2) {
        var locale = locale1 || locale2;
        if (!locale) {
            return [];
        }
        return Array.isArray(locale) ? locale : [locale];
    }
    function checkLocales(locales) {
        if (!locales.length) {
            throw Error('Not defined the property "locale".');
        }
        locales.forEach(function (locale) {
            if (!hasLocale(locale)) {
                throw Error("\"".concat(locale, "\" is not supported locale."));
            }
        });
    }

    var data$1 = {};
    /**
     * Get data for use in rules.
     */
    function getData(key) {
        return data$1[key];
    }
    /**
     * Set data for use in rules.
     */
    function setData(newData) {
        Object.keys(newData).forEach(function (key) {
            addLocale(key);
            data$1[key] = newData[key];
        });
    }

    var inlineElements = [
        'a',
        'abbr',
        'acronym',
        'b',
        'bdo',
        'big',
        'br',
        'button',
        'cite',
        'code',
        'dfn',
        'em',
        'i',
        'img',
        'input',
        'kbd',
        'label',
        'map',
        'object',
        'q',
        'samp',
        'script',
        'select',
        'small',
        'span',
        'strong',
        'sub',
        'sup',
        'textarea',
        'time',
        'tt',
        'var'
    ];

    var regExpUrl = new RegExp('(https?|file|ftp)://([a-zA-Z0-9/+-=%&:_.~?]+[a-zA-Z0-9#+]*)', 'g');
    var regExpNumber = '\\d+([.,]\\d+)?';
    var regExpDigit = /\d/;
    function isDigit(symbol) {
        return symbol.search(regExpDigit) > -1;
    }

    var privateLabel = '\uF000';
    var privateSeparateLabel = '\uF001';

    var SafeTags = /** @class */ (function () {
        function SafeTags() {
            this.groups = ['own', 'html', 'url'];
            this.hidden = {};
            this.counter = 0;
            var html = [
                ['<!--', '-->'],
                ['<!ENTITY', '>'],
                ['<!DOCTYPE', '>'],
                ['<\\?xml', '\\?>'],
                ['<!\\[CDATA\\[', '\\]\\]>']
            ];
            [
                'code',
                'kbd',
                'object',
                'pre',
                'samp',
                'script',
                'style',
                'var'
            ].forEach(function (tag) {
                html.push([
                    "<".concat(tag, "(\\s[^>]*?)?>"),
                    "</".concat(tag, ">")
                ]);
            });
            this.tags = {
                own: [],
                html: html.map(this.prepareRegExp),
                url: [regExpUrl]
            };
        }
        /**
         * Add own safe tag.
         */
        SafeTags.prototype.add = function (tag) {
            this.tags.own.push(this.prepareRegExp(tag));
        };
        /**
         * Show safe tags.
         */
        SafeTags.prototype.show = function (context, group) {
            var reReplace = new RegExp(privateLabel + 'tf\\d+' + privateLabel, 'g');
            var reSearch = new RegExp(privateLabel + 'tf\\d');
            var replaceLabel = function (match) {
                return context.safeTags.hidden[group][match] || match;
            };
            for (var i = 0, len = this.tags[group].length; i < len; i++) {
                context.text = context.text.replace(reReplace, replaceLabel);
                if (context.text.search(reSearch) === -1) {
                    break;
                }
            }
        };
        /**
         * Hide safe tags.
         */
        SafeTags.prototype.hide = function (context, group) {
            var _this = this;
            context.safeTags.hidden[group] = {};
            var pasteLabel = this.pasteLabel.bind(this, context, group);
            this.tags[group].forEach(function (tag) {
                context.text = context.text.replace(_this.prepareRegExp(tag), pasteLabel);
            });
        };
        /**
         * Hide HTML tags.
         */
        SafeTags.prototype.hideHTMLTags = function (context) {
            if (context.isHTML) {
                var pasteLabel = this.pasteLabel.bind(this, context, 'html');
                context.text = context.text
                    .replace(/<\/?[a-z][^]*?>/gi, pasteLabel) // Tags
                    .replace(/&lt;\/?[a-z][^]*?&gt;/gi, pasteLabel) // Escaping tags
                    .replace(/&[gl]t;/gi, pasteLabel);
            }
        };
        /**
         * Get previous label.
         */
        SafeTags.prototype.getPrevLabel = function (text, position) {
            for (var i = position - 1; i >= 0; i--) {
                if (text[i] === privateLabel) {
                    return text.slice(i, position + 1);
                }
            }
            return '';
        };
        SafeTags.prototype.getNextLabel = function (text, position) {
            for (var i = position + 1; i < text.length; i++) {
                if (text[i] === privateLabel) {
                    return text.slice(position, i + 1);
                }
            }
            return '';
        };
        SafeTags.prototype.getTagByLabel = function (context, label) {
            var result = null;
            this.groups.some(function (group) {
                var value = context.safeTags.hidden[group][label];
                if (typeof value !== 'undefined') {
                    result = {
                        group: group,
                        value: value
                    };
                }
                return result;
            });
            return result;
        };
        SafeTags.prototype.getTagInfo = function (tag) {
            if (!tag) {
                return null;
            }
            var result = { group: tag.group };
            switch (tag.group) {
                case 'html':
                    result.name = tag.value.split(/[<\s>]/)[1];
                    result.isInline = inlineElements.indexOf(result.name) > -1;
                    result.isClosing = tag.value.search(/^<\//) > -1;
                    break;
                case 'url':
                    result.isInline = true;
                    break;
                case 'own':
                    result.isInline = false;
                    break;
            }
            return result;
        };
        SafeTags.prototype.pasteLabel = function (context, group, match) {
            var safeTags = context.safeTags;
            var key = privateLabel + 'tf' + safeTags.counter + privateLabel;
            safeTags.hidden[group][key] = match;
            safeTags.counter++;
            return key;
        };
        SafeTags.prototype.prepareRegExp = function (tag) {
            if (tag instanceof RegExp) {
                return tag;
            }
            var startTag = tag[0], endTag = tag[1], middle = tag[2];
            return new RegExp(startTag +
                (typeof middle === 'undefined' ? '[^]*?' : middle) +
                endTag, 'gi');
        };
        SafeTags.prototype.getPrevTagInfo = function (context, text, pos) {
            var prevLabel = this.getPrevLabel(text, pos - 1);
            if (prevLabel) {
                var prevTag = this.getTagByLabel(context, prevLabel);
                if (prevTag) {
                    return this.getTagInfo(prevTag);
                }
            }
            return null;
        };
        SafeTags.prototype.getNextTagInfo = function (context, text, pos) {
            var nextLabel = this.getNextLabel(text, pos + 1);
            if (nextLabel) {
                var nextTag = this.getTagByLabel(context, nextLabel);
                if (nextTag) {
                    return this.getTagInfo(nextTag);
                }
            }
            return null;
        };
        return SafeTags;
    }());

    function repeat(symbol, count) {
        var result = '';
        for (;;) {
            if ((count & 1) === 1) {
                result += symbol;
            }
            count >>>= 1;
            if (count === 0) {
                break;
            }
            symbol += symbol;
        }
        return result;
    }
    function replaceNbsp$1(text) {
        return text.replace(/\u00A0/g, ' ');
    }
    function replace(text, re) {
        for (var i = 0; i < re.length; i++) {
            text = text.replace(re[i][0], re[i][1]);
        }
        return text;
    }
    function isHTML(text) {
        return text.search(/(<\/?[a-z]|<!|&[lg]t;)/i) !== -1;
    }
    function removeCR(text) {
        return text.replace(/\r\n?/g, '\n');
    }
    function fixLineEnding(text, type) {
        if (type === 'CRLF') { // Windows
            return text.replace(/\n/g, '\r\n');
        }
        else if (type === 'CR') { // Mac
            return text.replace(/\n/g, '\r');
        }
        return text;
    }

    /**
     * Get a deep copy of a object.
     */
    function deepCopy(obj) {
        return typeof obj === 'object' ? JSON.parse(JSON.stringify(obj)) : obj;
    }

    var groupIndexes = {
        symbols: 110,
        'number': 150,
        space: 210,
        dash: 310,
        punctuation: 410,
        nbsp: 510,
        money: 710,
        date: 810,
        other: 910,
        optalign: 1010,
        typo: 1110,
        html: 1210
    };

    var DEFAULT_RULE_INDEX = 0;
    var DEFAULT_QUEUE_NAME = 'default';
    var rules = [];
    var innerRules = [];
    function addInnerRule(rule) {
        innerRules.push(prepareRule(rule));
    }
    function addRule(rule) {
        var preparedRule = prepareRule(rule);
        addLocale(preparedRule.locale);
        rules.push(preparedRule);
    }
    function sortRules(rules) {
        rules.sort(function (a, b) { return a.index > b.index ? 1 : -1; });
    }
    function getRules() {
        var result = __spreadArray([], rules, true);
        sortRules(result);
        return result;
    }
    function getInnerRules() {
        return __spreadArray([], innerRules, true);
    }
    function getRuleIndex(rule) {
        if (typeof rule.index === 'number') {
            return rule.index;
        }
        var _a = rule.name.split('/'), group = _a[1];
        var groupIndex = groupIndexes[group];
        if (typeof groupIndex === 'undefined') {
            groupIndex = DEFAULT_RULE_INDEX;
        }
        if (typeof rule.index === 'string') {
            return groupIndex + parseInt(rule.index, 10);
        }
        return groupIndex;
    }
    function prepareRule(rule) {
        var _a = rule.name.split('/'), locale = _a[0], group = _a[1], shortName = _a[2];
        var preparedRule = {
            name: rule.name,
            shortName: shortName,
            handler: rule.handler,
            queue: rule.queue || DEFAULT_QUEUE_NAME,
            enabled: rule.disabled === true ? false : true,
            locale: locale,
            group: group,
            index: getRuleIndex(rule),
            settings: rule.settings,
            live: rule.live,
            htmlAttrs: rule.htmlAttrs,
        };
        return preparedRule;
    }

    var PACKAGE_VERSION = '7.4.0';

    function prepareHtmlEntity(htmlEntity) {
        var result = {
            type: (htmlEntity === null || htmlEntity === void 0 ? void 0 : htmlEntity.type) || 'default',
            list: htmlEntity === null || htmlEntity === void 0 ? void 0 : htmlEntity.list,
            onlyInvisible: Boolean(htmlEntity === null || htmlEntity === void 0 ? void 0 : htmlEntity.onlyInvisible),
        };
        return result;
    }
    function prepareLineEnding(lineEnding) {
        return lineEnding || 'LF';
    }
    function preparePrefs(prefs) {
        var result = {
            locale: prepareLocale(prefs.locale),
            lineEnding: prepareLineEnding(prefs.lineEnding),
            live: Boolean(prefs.live),
            ruleFilter: prefs.ruleFilter,
            enableRule: prefs.enableRule,
            disableRule: prefs.disableRule,
            processingSeparateParts: prefs.processingSeparateParts,
            htmlEntity: prepareHtmlEntity(prefs.htmlEntity),
        };
        return result;
    }
    function prepareContextPrefs(prefs, executePrefs) {
        var result = __assign({}, prefs);
        if (!executePrefs) {
            return result;
        }
        if ('locale' in executePrefs) {
            result.locale = prepareLocale(executePrefs.locale);
        }
        if ('htmlEntity' in executePrefs) {
            result.htmlEntity = prepareHtmlEntity(executePrefs.htmlEntity);
        }
        if ('lineEnding' in executePrefs) {
            result.lineEnding = prepareLineEnding(executePrefs.lineEnding);
        }
        if ('processingSeparateParts' in executePrefs) {
            result.processingSeparateParts = executePrefs.processingSeparateParts;
        }
        if ('ruleFilter' in executePrefs) {
            result.ruleFilter = executePrefs.ruleFilter;
        }
        return result;
    }

    var Typograf = /** @class */ (function () {
        function Typograf(prefs) {
            var _this = this;
            this.rules = [];
            this.innerRules = [];
            this.rulesByQueues = {};
            this.innerRulesByQueues = {};
            this.separatePartsTags = [
                'title',
                'p',
                'h[1-6]',
                'select',
                'legend',
            ];
            this.prefs = preparePrefs(prefs);
            checkLocales(this.prefs.locale);
            this.safeTags = new SafeTags();
            this.settings = {};
            this.enabledRules = {};
            this.innerRulesByQueues = {};
            this.innerRules = getInnerRules();
            this.innerRules.forEach(function (rule) {
                _this.innerRulesByQueues[rule.queue] = _this.innerRulesByQueues[rule.queue] || [];
                _this.innerRulesByQueues[rule.queue].push(rule);
            });
            this.rulesByQueues = {};
            this.rules = getRules();
            this.rules.forEach(function (rule) {
                _this.prepareRuleSettings(rule);
                _this.rulesByQueues[rule.queue] = _this.rulesByQueues[rule.queue] || [];
                _this.rulesByQueues[rule.queue].push(rule);
            });
            this.prefs.disableRule && this.disableRule(this.prefs.disableRule);
            this.prefs.enableRule && this.enableRule(this.prefs.enableRule);
        }
        Typograf.addRule = function (rule) {
            addRule(rule);
        };
        Typograf.addRules = function (rules) {
            var _this = this;
            rules.forEach(function (item) {
                _this.addRule(item);
            });
        };
        /**
         * Add internal rule.
         * Internal rules are executed before main rules.
         */
        Typograf.addInnerRule = function (rule) {
            addInnerRule(rule);
        };
        Typograf.addInnerRules = function (rules) {
            var _this = this;
            rules.forEach(function (item) {
                _this.addInnerRule(item);
            });
        };
        Typograf.getRule = function (ruleName) {
            var rule = null;
            var rules = getRules();
            rules.some(function (item) {
                if (item.name === ruleName) {
                    rule = item;
                    return true;
                }
                return false;
            });
            return rule;
        };
        Typograf.getRules = function () {
            return getRules();
        };
        Typograf.getInnerRules = function () {
            return getInnerRules();
        };
        Typograf.getLocales = function () {
            return getLocales();
        };
        Typograf.addLocale = function (locale) {
            addLocale(locale);
        };
        Typograf.hasLocale = function (locale) {
            return hasLocale(locale);
        };
        Typograf.setData = function (data) {
            setData(data);
        };
        Typograf.getData = function (key) {
            return getData(key);
        };
        /**
         * Execute typographical rules for text.
         */
        Typograf.prototype.execute = function (text, prefs) {
            text = '' + text;
            if (!text) {
                return '';
            }
            var contextPrefs = prepareContextPrefs(this.prefs, prefs);
            checkLocales(contextPrefs.locale);
            var context = this.prepareContext(text, contextPrefs);
            return this.process(context);
        };
        Typograf.prototype.getSetting = function (ruleName, setting) {
            return this.settings[ruleName] && this.settings[ruleName][setting];
        };
        Typograf.prototype.setSetting = function (ruleName, setting, value) {
            this.settings[ruleName] = this.settings[ruleName] || {};
            this.settings[ruleName][setting] = value;
        };
        Typograf.prototype.isEnabledRule = function (ruleName) {
            return this.enabledRules[ruleName] !== false;
        };
        Typograf.prototype.isDisabledRule = function (ruleName) {
            return !this.enabledRules[ruleName];
        };
        Typograf.prototype.enableRule = function (ruleName) {
            return this.enable(ruleName, true);
        };
        Typograf.prototype.disableRule = function (ruleName) {
            return this.enable(ruleName, false);
        };
        /**
         * Add safe tag.
         *
         * @example
         * // const typograf = new Typograf({ locale: 'ru' });
         * // typograf.addSafeTag('<mytag>', '</mytag>');
         * // typograf.addSafeTag('<mytag>', '</mytag>', '.*?');
         * // typograf.addSafeTag(/<mytag>.*?</mytag>/gi);
        */
        Typograf.prototype.addSafeTag = function (startTag, endTag, middle) {
            var tag = startTag instanceof RegExp ? startTag : [startTag, endTag, middle];
            this.safeTags.add(tag);
        };
        Typograf.prototype.prepareContext = function (text, prefs) {
            var context = {
                text: text,
                isHTML: isHTML(text),
                prefs: prefs,
                getData: function (key) {
                    if (key === 'char') {
                        return prefs.locale.map(function (item) {
                            return getData(item + '/' + key);
                        }).join('');
                    }
                    else {
                        return getData(prefs.locale[0] + '/' + key);
                    }
                },
                safeTags: this.safeTags,
            };
            return context;
        };
        Typograf.prototype.splitBySeparateParts = function (context) {
            if (!context.isHTML || context.prefs.processingSeparateParts === false) {
                return [context.text];
            }
            var text = [];
            var reTags = new RegExp('<(' + this.separatePartsTags.join('|') + ')(\\s[^>]*?)?>[^]*?</\\1>', 'gi');
            var position = 0;
            context.text.replace(reTags, function ($0, $1, $2, itemPosition) {
                if (position !== itemPosition) {
                    text.push((position ? privateSeparateLabel : '') +
                        context.text.slice(position, itemPosition) +
                        privateSeparateLabel);
                }
                text.push($0);
                position = itemPosition + $0.length;
                return $0;
            });
            text.push(position ?
                (privateSeparateLabel + context.text.slice(position, context.text.length)) :
                context.text);
            return text;
        };
        Typograf.prototype.process = function (context) {
            var _this = this;
            context.text = removeCR(context.text);
            this.executeRules(context, 'start');
            this.safeTags.hide(context, 'own');
            this.executeRules(context, 'hide-safe-tags-own');
            this.safeTags.hide(context, 'html');
            this.executeRules(context, 'hide-safe-tags-html');
            var isRootHTML = context.isHTML;
            var re = new RegExp(privateSeparateLabel, 'g');
            context.text = this.splitBySeparateParts(context).map(function (item) {
                context.text = item;
                context.isHTML = isHTML(item);
                _this.safeTags.hideHTMLTags(context);
                _this.safeTags.hide(context, 'url');
                _this.executeRules(context, 'hide-safe-tags-url');
                _this.executeRules(context, 'hide-safe-tags');
                htmlEntities.toUtf(context);
                if (context.prefs.live) {
                    context.text = replaceNbsp$1(context.text);
                }
                _this.executeRules(context, 'utf');
                _this.executeRules(context);
                htmlEntities.restore(context);
                _this.executeRules(context, 'html-entities');
                _this.safeTags.show(context, 'url');
                _this.executeRules(context, 'show-safe-tags-url');
                return context.text.replace(re, '');
            }).join('');
            context.isHTML = isRootHTML;
            this.safeTags.show(context, 'html');
            this.executeRules(context, 'show-safe-tags-html');
            this.safeTags.show(context, 'own');
            this.executeRules(context, 'show-safe-tags-own');
            this.executeRules(context, 'end');
            return fixLineEnding(context.text, context.prefs.lineEnding);
        };
        Typograf.prototype.executeRules = function (context, queue) {
            var _this = this;
            if (queue === void 0) { queue = DEFAULT_QUEUE_NAME; }
            var rules = this.rulesByQueues[queue];
            var innerRules = this.innerRulesByQueues[queue];
            innerRules && innerRules.forEach(function (rule) {
                _this.ruleIterator(context, rule);
            });
            rules && rules.forEach(function (rule) {
                _this.ruleIterator(context, rule);
            });
        };
        Typograf.prototype.ruleIterator = function (context, rule) {
            if ((context.prefs.live === true && rule.live === false) || (context.prefs.live === false && rule.live === true)) {
                return;
            }
            if ((rule.locale === 'common' || rule.locale === context.prefs.locale[0]) && this.isEnabledRule(rule.name)) {
                if (context.prefs.ruleFilter && !context.prefs.ruleFilter(rule)) {
                    return;
                }
                this.onBeforeRule && this.onBeforeRule(rule.name, context);
                context.text = rule.handler.call(this, context.text, this.settings[rule.name], context);
                this.onAfterRule && this.onAfterRule(rule.name, context);
            }
        };
        Typograf.prototype.prepareRuleSettings = function (rule) {
            this.settings[rule.name] = deepCopy(rule.settings);
            this.enabledRules[rule.name] = rule.enabled;
        };
        Typograf.prototype.enable = function (ruleName, enabled) {
            var _this = this;
            if (Array.isArray(ruleName)) {
                ruleName.forEach(function (item) {
                    _this.enableByMask(item, enabled);
                });
            }
            else {
                this.enableByMask(ruleName, enabled);
            }
        };
        Typograf.prototype.enableByMask = function (ruleName, enabled) {
            var _this = this;
            if (!ruleName) {
                return;
            }
            if (ruleName.search(/\*/) !== -1) {
                var re_1 = new RegExp(ruleName
                    .replace(/\//g, '\\/')
                    .replace(/\*/g, '.*'));
                this.rules.forEach(function (el) {
                    var name = el.name;
                    if (re_1.test(name)) {
                        _this.enabledRules[name] = enabled;
                    }
                });
            }
            else {
                this.enabledRules[ruleName] = enabled;
            }
        };
        Typograf.groups = [];
        Typograf.titles = {};
        Typograf.version = PACKAGE_VERSION;
        return Typograf;
    }());

    var common = {
        'common/char': 'a-z',
        'common/dash': '--?|‒|–|—', // --, &#8210, &ndash, &mdash
        'common/quote': '«‹»›„“‟”"',
    };

    var be = {
        'be/char': 'абвгдежзйклмнопрстуфхцчшыьэюяёіўґ',
        'be/quote': {
            left: '«“',
            right: '»”',
        }
    };

    var bg = {
        'bg/char': 'абвгдежзийклмнопрстуфхцчшщъьюя',
        'bg/quote': {
            left: '„’',
            right: '“’',
        }
    };

    var ca = {
        'ca/char': 'abcdefghijlmnopqrstuvxyzàçèéíïòóúü',
        'ca/quote': {
            left: '«“',
            right: '»”',
        }
    };

    var cs = {
        'cs/char': 'a-záéíóúýčďěňřšťůž',
        'cs/quote': {
            left: '„‚',
            right: '“‘',
        }
    };

    var da = {
        'da/char': 'a-zåæø',
        'da/quote': {
            left: '»›',
            right: '«‹',
        }
    };

    var de = {
        'de/char': 'a-zßäöü',
        'de/quote': {
            left: '„‚',
            right: '“‘',
        }
    };

    var el = {
        'el/char': 'ΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώϲάέήίόύώ',
        'el/quote': {
            left: '«“',
            right: '»”',
        }
    };

    var enGB = {
        'en-GB/char': 'a-z',
        'en-GB/quote': {
            left: '‘“',
            right: '’”',
        }
    };

    var enUS = {
        'en-US/char': 'a-z',
        'en-US/quote': {
            left: '“‘',
            right: '”’',
        },
        'en-US/shortWord': 'a|an|and|as|at|bar|but|by|for|if|in|nor|not|of|off|on|or|out|per|pro|so|the|to|up|via|yet',
    };

    var eo = {
        'eo/char': 'abcdefghijklmnoprstuvzĉĝĥĵŝŭ',
        'eo/quote': {
            left: '“‘',
            right: '”’',
        }
    };

    var es = {
        'es/char': 'a-záéíñóúü',
        'es/quote': {
            left: '«“',
            right: '»”',
        }
    };

    var et = {
        'et/char': 'abdefghijklmnoprstuvzäõöüšž',
        'et/quote': {
            left: '„«',
            right: '“»',
        }
    };

    var fi = {
        'fi/char': 'abcdefghijklmnopqrstuvyöäå',
        'fi/quote': {
            left: '”’',
            right: '”’',
        }
    };

    var fr = {
        'fr/char': 'a-zàâçèéêëîïôûüœæ',
        'fr/quote': {
            left: '«‹',
            right: '»›',
            spacing: true,
        }
    };

    var ga = {
        'ga/char': 'abcdefghilmnoprstuvwxyzáéíóú',
        'ga/quote': {
            left: '“‘',
            right: '”’',
        }
    };

    var hu = {
        'hu/char': 'a-záäéíóöúüőű',
        'hu/quote': {
            left: '„»',
            right: '”«',
        }
    };

    var it = {
        'it/char': 'a-zàéèìòù',
        'it/quote': {
            left: '«“',
            right: '»”',
        }
    };

    var lv = {
        'lv/char': 'abcdefghijklmnopqrstuvxzæœ',
        'lv/quote': {
            left: '«„',
            right: '»“',
        }
    };

    var nl = {
        'nl/char': 'a-zäçèéêëîïñöûü',
        'nl/quote': {
            left: '‘“',
            right: '’”',
        }
    };

    var no = {
        'no/char': 'a-zåæèéêòóôø',
        'no/quote': {
            left: '«’',
            right: '»’',
        }
    };

    var pl = {
        'pl/char': 'abcdefghijklmnoprstuvwxyzóąćęłńśźż',
        'pl/quote': {
            left: '„«',
            right: '”»',
        }
    };

    var ro = {
        'ro/char': 'abcdefghijklmnoprstuvxzîășț',
        'ro/quote': {
            left: '„«',
            right: '”»',
        }
    };

    var ru = {
        'ru/char': 'а-яё',
        'ru/dashBefore': '(^| |\\n)',
        'ru/dashAfter': '(?=[\u00A0 ,.?:!]|$)',
        'ru/dashAfterDe': '(?=[,.?:!]|[\u00A0 ][^А-ЯЁ]|$)',
        'ru/l': 'а-яёa-z',
        'ru/L': 'А-ЯЁA-Z',
        'ru/month': 'январь|февраль|март|апрель|май|июнь|июль|август|сентябрь|октябрь|ноябрь|декабрь',
        'ru/monthGenCase': 'января|февраля|марта|апреля|мая|июня|июля|августа|сентября|октября|ноября|декабря',
        'ru/monthPreCase': 'январе|феврале|марте|апреле|мае|июне|июле|августе|сентябре|октябре|ноябре|декабре',
        'ru/quote': {
            left: '«„‚',
            right: '»“‘',
            removeDuplicateQuotes: true,
        },
        'ru/shortMonth': 'янв|фев|мар|апр|ма[ейя]|июн|июл|авг|сен|окт|ноя|дек',
        'ru/shortWord': 'а|бы|в|во|да|до|же|за|и|из|к|ко|ли|на|не|ни|но|о|об|от|по|с|со|то|у',
        'ru/weekday': 'понедельник|вторник|среда|четверг|пятница|суббота|воскресенье',
    };

    var sk = {
        'sk/char': 'abcdefghijklmnoprstuvwxyzáäéíóôúýčďľňŕšťž',
        'sk/quote': {
            left: '„‚',
            right: '“‘',
        }
    };

    var sl = {
        'sl/char': 'a-zčšž',
        'sl/quote': {
            left: '„‚',
            right: '“‘',
        }
    };

    var sr = {
        'sr/char': 'abcdefghijklmnoprstuvzćčđšž',
        'sr/quote': {
            left: '„’',
            right: '”’',
        }
    };

    var sv = {
        'sv/char': 'a-zäåéö',
        'sv/quote': {
            left: '”’',
            right: '”’',
        }
    };

    var tr = {
        'tr/char': 'abcdefghijklmnoprstuvyzâçîöûüğış',
        'tr/quote': {
            left: '“‘',
            right: '”’',
        }
    };

    var uk = {
        'uk/char': 'абвгдежзийклмнопрстуфхцчшщьюяєіїґ',
        'uk/quote': {
            left: '«„',
            right: '»“',
        }
    };

    var data = [
        common,
        be,
        bg,
        ca,
        cs,
        da,
        de,
        el,
        enGB,
        enUS,
        eo,
        es,
        et,
        fi,
        fr,
        ga,
        hu,
        it,
        lv,
        nl,
        no,
        pl,
        ro,
        ru,
        sk,
        sl,
        sr,
        sv,
        tr,
        uk
    ];
    data.forEach(function (item) { return setData(item); });

    var eMailRule = {
        name: 'common/html/e-mail',
        queue: 'end',
        handler: function (text, _settings, context) {
            return context.isHTML ? text : text.replace(/(^|[\s;(])([\w\-.]{2,64})@([\w\-.]{2,64})\.([a-z]{2,64})([)\s.,!?]|$)/gi, '$1<a href="mailto:$2@$3.$4">$2@$3.$4</a>$5');
        },
        disabled: true,
        htmlAttrs: false,
    };

    var entityMap = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        '\'': '&#39;',
        '/': '&#x2F;'
    };
    var escapeRule = {
        name: 'common/html/escape',
        index: '+100',
        queue: 'end',
        handler: function (text) {
            return text.replace(/[&<>"'/]/g, function (key) { return entityMap[key]; });
        },
        disabled: true,
    };

    var nbrRule = {
        name: 'common/html/nbr',
        index: '+10',
        queue: 'end',
        handler: function (text) {
            return text.replace(/([^\n>])\n(?=[^\n])/g, '$1<br/>\n');
        },
        disabled: true,
        htmlAttrs: false,
    };

    var blockElements = [
        'address',
        'article',
        'aside',
        'blockquote',
        'canvas',
        'dd',
        'div',
        'dl',
        'fieldset',
        'figcaption',
        'figure',
        'footer',
        'form',
        'h1',
        'h2',
        'h3',
        'h4',
        'h5',
        'h6',
        'header',
        'hgroup',
        'hr',
        'li',
        'main',
        'nav',
        'noscript',
        'ol',
        'output',
        'p',
        'pre',
        'section',
        'table',
        'tfoot',
        'ul',
        'video'
    ];

    var blockRe = new RegExp('<(' + blockElements.join('|') + ')[>\\s]');
    var separator = '\n\n';
    var pRule = {
        name: 'common/html/p',
        index: '+5',
        queue: 'end',
        handler: function (text) {
            var buffer = text.split(separator);
            buffer.forEach(function (text, i, data) {
                if (!text.trim()) {
                    return;
                }
                if (!blockRe.test(text)) {
                    data[i] = text.replace(/^(\s*)/, '$1<p>').replace(/(\s*)$/, '</p>$1');
                }
            });
            return buffer.join(separator);
        },
        disabled: true,
        htmlAttrs: false,
    };

    var processingAttrsRule = {
        name: 'common/html/processingAttrs',
        queue: 'hide-safe-tags-own', // After "hide-safe-tags-own", before "hide-safe-tags-html".
        handler: function (text, settings, context) {
            var _this = this;
            var reAttrs = new RegExp('(^|\\s)(' + settings.attrs.join('|') + ')=("[^"]*?"|\'[^\']*?\')', 'gi');
            var prefs = deepCopy(context.prefs);
            prefs.ruleFilter = function (rule) { return rule.htmlAttrs !== false; };
            return text.replace(/(<[-\w]+\s)([^>]+?)(?=>)/g, function (_match, tagName, attrs) {
                var resultAttrs = attrs.replace(reAttrs, function (_submatch, space, attrName, attrValue) {
                    var lquote = attrValue[0];
                    var rquote = attrValue[attrValue.length - 1];
                    var value = attrValue.slice(1, -1);
                    return space + attrName + '=' + lquote + _this.execute(value, prefs) + rquote;
                });
                return tagName + resultAttrs;
            });
        },
        settings: {
            attrs: ['title', 'placeholder']
        },
        disabled: true,
        htmlAttrs: false,
    };

    var quotRule = {
        name: 'common/html/quot',
        queue: 'hide-safe-tags',
        handler: function (text) {
            return text.replace(/&quot;/g, '"');
        },
    };

    var stripTagsRule = {
        name: 'common/html/stripTags',
        index: '+99',
        queue: 'end',
        handler: function (text) {
            return text.replace(/<[^>]+>/g, '');
        },
        disabled: true,
    };

    var urlRule = {
        name: 'common/html/url',
        queue: 'end',
        handler: function (text, _settings, context) {
            return context.isHTML ? text : text.replace(regExpUrl, function ($0, protocol, path) {
                path = path
                    .replace(/([^/]+\/?)(\?|#)$/, '$1') // Remove ending ? and #
                    .replace(/^([^/]+)\/$/, '$1'); // Remove ending /
                if (protocol === 'http') {
                    path = path.replace(/^([^/]+)(:80)([^\d]|\/|$)/, '$1$3'); // Remove 80 port
                }
                else if (protocol === 'https') {
                    path = path.replace(/^([^/]+)(:443)([^\d]|\/|$)/, '$1$3'); // Remove 443 port
                }
                var url = path;
                var fullUrl = protocol + '://' + path;
                var firstPart = '<a href="' + fullUrl + '">';
                if (protocol === 'http' || protocol === 'https') {
                    url = url.replace(/^www\./, '');
                    return firstPart + (protocol === 'http' ? url : protocol + '://' + url) + '</a>';
                }
                return firstPart + fullUrl + '</a>';
            });
        },
        disabled: true,
        htmlAttrs: false,
    };

    Typograf.addRules([
        eMailRule,
        escapeRule,
        nbrRule,
        pRule,
        processingAttrsRule,
        quotRule,
        stripTagsRule,
        urlRule,
    ]);

    var afterNumberRule = {
        name: 'common/nbsp/afterNumber',
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var re = '(^|\\s)(\\d{1,5}) ([' + char + ']+)';
            return text.replace(new RegExp(re, 'gi'), '$1$2\u00A0$3');
        },
        disabled: true,
    };

    var afterParagraphMarkRule = {
        name: 'common/nbsp/afterParagraphMark',
        handler: function (text) {
            return text.replace(/¶ ?(?=\d)/g, '¶\u00A0');
        },
    };

    var afterSectionMarkRule = {
        name: 'common/nbsp/afterSectionMark',
        handler: function (text, _settings, context) {
            // \u2009 - THIN SPACE
            // \u202F - NARROW NO-BREAK SPACE
            var locale = context.prefs.locale[0];
            return text.replace(/§[ \u00A0\u2009]?(?=\d|I|V|X)/g, locale === 'ru' ? '§\u202F' : '§\u00A0');
        },
    };

    var afterShortWordRule = {
        name: 'common/nbsp/afterShortWord',
        handler: function (text, settings, context) {
            var lengthShortWord = settings.lengthShortWord, useShortWordList = settings.useShortWordList;
            var quote = getData('common/quote');
            var char = context.getData('char');
            var shortWord = context.getData('shortWord');
            var before = ' \u00A0(' + privateLabel + quote;
            var subStr = useShortWordList && shortWord !== undefined
                ? '(^|[' + before + '])(' + shortWord + ') '
                : '(^|[' + before + '])([' + char + ']{1,' + lengthShortWord + '}) ';
            var newSubStr = '$1$2\u00A0';
            var re = new RegExp(subStr, 'gim');
            return text
                .replace(re, newSubStr)
                .replace(re, newSubStr);
        },
        settings: {
            lengthShortWord: 2,
            useShortWordList: false,
        },
    };

    var beforeShortLastNumberRule = {
        name: 'common/nbsp/beforeShortLastNumber',
        handler: function (text, settings, context) {
            var quote = context.getData('quote');
            var ch = context.getData('char');
            var CH = ch.toUpperCase();
            var re = new RegExp('([' + ch + CH +
                ']) (?=\\d{1,' + settings.lengthLastNumber +
                '}[-+−%\'"' + quote.right + ')]?([.!?…]( [' +
                CH + ']|$)|$))', 'gm');
            return text.replace(re, '$1\u00A0');
        },
        live: false,
        settings: {
            lengthLastNumber: 2,
        },
    };

    var beforeShortLastWordRule = {
        name: 'common/nbsp/beforeShortLastWord',
        handler: function (text, settings, context) {
            var ch = context.getData('char');
            var CH = ch.toUpperCase();
            var re = new RegExp('([' + ch + '\\d]) ([' +
                ch + CH + ']{1,' + settings.lengthLastWord +
                '}[.!?…])( [' + CH + ']|$)', 'g');
            return text.replace(re, '$1\u00A0$2$3');
        },
        settings: {
            lengthLastWord: 3,
        },
    };

    var dpiRule = {
        name: 'common/nbsp/dpi',
        handler: function (text) {
            return text.replace(/(\d) ?(lpi|dpi)(?!\w)/, '$1\u00A0$2');
        },
    };

    function replaceNbsp($0, $1, $2, $3) {
        return $1 + $2.replace(/([^\u00A0])\u00A0([^\u00A0])/g, '$1 $2') + $3;
    }
    var nowrapRule = {
        name: 'common/nbsp/nowrap',
        queue: 'end',
        handler: function (text) {
            return text
                .replace(/(<nowrap>)(.*?)(<\/nowrap>)/g, replaceNbsp)
                .replace(/(<nobr>)(.*?)(<\/nobr>)/g, replaceNbsp);
        },
    };

    var replaceNbspRule = {
        name: 'common/nbsp/replaceNbsp',
        queue: 'utf',
        live: false,
        handler: replaceNbsp$1,
        disabled: true,
    };

    Typograf.addRules([
        afterNumberRule,
        afterParagraphMarkRule,
        afterSectionMarkRule,
        afterShortWordRule,
        beforeShortLastNumberRule,
        beforeShortLastWordRule,
        dpiRule,
        nowrapRule,
        replaceNbspRule,
    ]);

    var digitGroupingRule = {
        name: 'common/number/digitGrouping',
        index: '310',
        disabled: true,
        handler: function (text, settings) {
            return text
                .replace(new RegExp("(^ ?|\\D |".concat(privateLabel, ")(\\d{1,3}([ \u00A0\u202F\u2009]\\d{3})+)(?! ?[\\d-])"), 'gm'), function ($0, $1, $2) { return $1 + $2.replace(/\s/g, settings.space); })
                // https://www.bipm.org/utils/common/pdf/si-brochure/SI-Brochure-9-EN.pdf #5.4.4
                .replace(/(\d{5,}([.,]\d+)?)/g, function ($0, $1) {
                var decimalMarker = $1.match(/[.,]/);
                var parts = decimalMarker ? $1.split(decimalMarker) : [$1];
                var integerPart = parts[0];
                var fractionalPart = parts[1];
                integerPart = integerPart.replace(/(\d)(?=(\d{3})+([^\d]|$))/g, '$1' + settings.space);
                return decimalMarker ?
                    integerPart + decimalMarker + fractionalPart :
                    integerPart;
            });
        },
        settings: {
            space: '\u202F',
        },
    };

    var fractionRule = {
        name: 'common/number/fraction',
        handler: function (text) {
            return text
                .replace(/(^|\D)1\/2(\D|$)/g, '$1½$2')
                .replace(/(^|\D)1\/4(\D|$)/g, '$1¼$2')
                .replace(/(^|\D)3\/4(\D|$)/g, '$1¾$2');
        },
    };

    var mathSignsRule = {
        name: 'common/number/mathSigns',
        handler: function (text) {
            return replace(text, [
                [/!=/g, '≠'],
                [/<=/g, '≤'],
                [/(^|[^=])>=/g, '$1≥'],
                [/<=>/g, '⇔'],
                [/<</g, '≪'],
                [/>>/g, '≫'],
                [/~=/g, '≅'],
                [/(^|[^+])\+-/g, '$1±']
            ]);
        }
    };

    var timesRule = {
        name: 'common/number/times',
        handler: function (text) {
            return text.replace(/(\d)[ \u00A0]?[xх][ \u00A0]?(\d)/g, '$1×$2');
        },
    };

    Typograf.addRules([
        digitGroupingRule,
        fractionRule,
        mathSignsRule,
        timesRule,
    ]);

    var delBOMRule = {
        name: 'common/other/delBOM',
        queue: 'start',
        index: -1,
        handler: function (text) {
            if (text.charCodeAt(0) === 0xFEFF) {
                return text.slice(1);
            }
            return text;
        },
    };

    var repeatWordRule = {
        name: 'common/other/repeatWord',
        handler: function (text, settings, context) {
            var quote = getData('common/quote');
            var char = context.getData('char');
            var punc = '[;:,.?! \n' + quote + ']';
            var re = new RegExp('(' + punc + '|^)' +
                '([' + char + ']{' + settings.min + ',}) ' +
                '\\2(' + punc + '|$)', 'gi');
            return text.replace(re, '$1$2$3');
        },
        settings: { min: 2 },
        disabled: true,
    };

    Typograf.addRules([
        delBOMRule,
        repeatWordRule,
    ]);

    var apostropheRule = {
        name: 'common/punctuation/apostrophe',
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var letters = '([' + char + '])';
            var re = new RegExp(letters + '\'' + letters, 'gi');
            return text.replace(re, '$1’$2');
        },
    };

    var delDoublePunctuationRule = {
        name: 'common/punctuation/delDoublePunctuation',
        handler: function (text) {
            return text
                .replace(/(^|[^,]),,(?!,)/g, '$1,')
                .replace(/(^|[^:])::(?!:)/g, '$1:')
                .replace(/(^|[^!?.])\.\.(?!\.)/g, '$1.')
                .replace(/(^|[^;]);;(?!;)/g, '$1;')
                .replace(/(^|[^?])\?\?(?!\?)/g, '$1?');
        },
    };

    var hellipRule = {
        name: 'common/punctuation/hellip',
        handler: function (text, _settings, context) {
            return context.prefs.locale[0] === 'ru' ?
                text.replace(/(^|[^.])\.{3,4}(?=[^.]|$)/g, '$1…') :
                text.replace(/(^|[^.])\.{3}(\.?)(?=[^.]|$)/g, '$1…$2');
        },
    };

    var MAX_LEVEL_WITH_ERRORS = 2;
    var Quote = /** @class */ (function () {
        function Quote() {
            this.bufferQuotes = {
                left: '\uF005\uF006\uF007',
                right: '\uF008\uF009\uF0A0',
            };
            this.beforeLeft = ' \n\t\u00a0[(';
            this.afterRight = ' \n\t\u00a0!?.:;#*,…)\\]';
        }
        Quote.prototype.process = function (params) {
            var text = params.context.text;
            var count = this.count(text);
            if (!count.total) {
                return text;
            }
            var originalSettings = params.settings;
            var isEqualQuotes = params.settings.left[0] === params.settings.right[0];
            // For SW, FI
            if (isEqualQuotes) {
                params.settings = deepCopy(params.settings);
                params.settings.left = this.bufferQuotes.left.slice(0, params.settings.left.length);
                params.settings.right = this.bufferQuotes.right.slice(0, params.settings.right.length);
            }
            // For FR
            if (params.settings.spacing) {
                text = this.removeSpacing(text, params.settings);
            }
            text = this.set(text, params);
            // For FR
            if (params.settings.spacing) {
                text = this.setSpacing(text, params.settings);
            }
            // For RU
            if (params.settings.removeDuplicateQuotes) {
                text = this.removeDuplicates(text, params.settings);
            }
            // For SW, FI
            if (isEqualQuotes) {
                text = this.returnOriginalQuotes(text, originalSettings, params.settings);
                params.settings = originalSettings;
            }
            return text;
        };
        Quote.prototype.returnOriginalQuotes = function (text, originalSettings, bufferSettings) {
            var buffer = {};
            for (var i = 0; i < bufferSettings.left.length; i++) {
                buffer[bufferSettings.left[i]] = originalSettings.left[i];
                buffer[bufferSettings.right[i]] = originalSettings.right[i];
            }
            return text.replace(new RegExp('[' + bufferSettings.left + bufferSettings.right + ']', 'g'), function (quote) {
                return buffer[quote];
            });
        };
        Quote.prototype.count = function (text) {
            var count = { total: 0 };
            text.replace(new RegExp('[' + getData('common/quote') + ']', 'g'), function (quote) {
                if (!count[quote]) {
                    count[quote] = 0;
                }
                count[quote]++;
                count.total++;
                return quote;
            });
            return count;
        };
        Quote.prototype.removeDuplicates = function (text, settings) {
            var lquote = settings.left[0];
            var lquote2 = settings.left[1] || lquote;
            var rquote = settings.right[0];
            if (lquote !== lquote2) {
                return text;
            }
            return text
                // ««word» word» -> «word» word»
                .replace(new RegExp(lquote + lquote, 'g'), lquote)
                // «word «word»» -> «word «word»
                .replace(new RegExp(rquote + rquote, 'g'), rquote);
        };
        Quote.prototype.removeSpacing = function (text, settings) {
            for (var i = 0, len = settings.left.length; i < len; i++) {
                var lquote = settings.left[i];
                var rquote = settings.right[i];
                text = text
                    .replace(new RegExp(lquote + '([ \u202F\u00A0])', 'g'), lquote)
                    .replace(new RegExp('([ \u202F\u00A0])' + rquote, 'g'), rquote);
            }
            return text;
        };
        Quote.prototype.setSpacing = function (text, settings) {
            for (var i = 0, len = settings.left.length; i < len; i++) {
                var lquote = settings.left[i];
                var rquote = settings.right[i];
                text = text
                    .replace(new RegExp(lquote + '([^\u202F])', 'g'), lquote + '\u202F$1')
                    .replace(new RegExp('([^\u202F])' + rquote, 'g'), '$1\u202F' + rquote);
            }
            return text;
        };
        Quote.prototype.set = function (text, params) {
            var quotes = getData('common/quote');
            var lquote = params.settings.left[0];
            var lquote2 = params.settings.left[1] || lquote;
            var rquote = params.settings.right[0];
            var reL = new RegExp('(^|[' + this.beforeLeft + '])([' + quotes + ']+)(?=[^\\s' + privateLabel + '])', 'gim');
            var reR = new RegExp('([^\\s' + privateLabel + '])([' + quotes + ']+)(?=[' + this.afterRight + ']|$)', 'gim');
            text = text
                .replace(reL, function ($0, $1, $2) { return $1 + repeat(lquote, $2.length); })
                .replace(reR, function ($0, $1, $2) { return $1 + repeat(rquote, $2.length); });
            text = this.setAboveTags(text, params);
            if (lquote !== lquote2) {
                text = this.setInner(text, params.settings);
            }
            return text;
        };
        Quote.prototype.setAboveTags = function (text, params) {
            var _this = this;
            var quotes = getData('common/quote');
            var lquote = params.settings.left[0];
            var rquote = params.settings.right[0];
            return text.replace(new RegExp('(^|.)([' + quotes + ']+)(.|$)', 'gm'), function (original, prev, quote, next, pos) {
                if (prev !== privateLabel && next !== privateLabel) {
                    return original;
                }
                if (prev === privateLabel && next === privateLabel) {
                    if (quote === '"') {
                        return prev + _this.getAboveTwoTags(text, pos + 1, params) + next;
                    }
                    return original;
                }
                if (prev === privateLabel) {
                    var hasRight = _this.afterRight.indexOf(next) > -1;
                    var prevInfo = params.safeTags.getPrevTagInfo(params.context, text, pos + 1);
                    var newQuote = lquote;
                    if (hasRight && prevInfo && prevInfo.group === 'html') {
                        newQuote = prevInfo.isClosing ? rquote : lquote;
                    }
                    else {
                        newQuote = !next || hasRight ? rquote : lquote;
                    }
                    return prev + newQuote.repeat(quote.length) + next;
                }
                else {
                    var hasLeft = _this.beforeLeft.indexOf(prev) > -1;
                    var nextInfo = params.safeTags.getNextTagInfo(params.context, text, pos + 1);
                    var newQuote = lquote;
                    if (hasLeft && nextInfo && nextInfo.group === 'html') {
                        newQuote = nextInfo.isClosing ? rquote : lquote;
                    }
                    else {
                        newQuote = !prev || hasLeft ? lquote : rquote;
                    }
                    return prev + newQuote.repeat(quote.length) + next;
                }
            });
        };
        Quote.prototype.getAboveTwoTags = function (text, pos, params) {
            var prevInfo = params.safeTags.getPrevTagInfo(params.context, text, pos);
            var nextInfo = params.safeTags.getNextTagInfo(params.context, text, pos);
            if (prevInfo) {
                if (prevInfo.group === 'html') {
                    if (!prevInfo.isClosing) {
                        return params.settings.left[0];
                    }
                    if (nextInfo && nextInfo.isClosing && prevInfo.isClosing) {
                        return params.settings.right[0];
                    }
                }
            }
            return text[pos];
        };
        Quote.prototype.setInner = function (text, settings) {
            var lquote = settings.left[0];
            var rquote = settings.right[0];
            var minLevel = 0;
            var maxLevel = this.getMaxLevel(text, lquote, rquote, settings.left.length);
            var level = minLevel;
            var result = '';
            for (var i = 0, len = text.length; i < len; i++) {
                var letter = text[i];
                if (letter === lquote) {
                    result += settings.left[level > maxLevel - 1 ? maxLevel - 1 : level];
                    level++;
                    if (level > maxLevel) {
                        level = maxLevel;
                    }
                }
                else if (letter === rquote) {
                    level--;
                    if (level < minLevel) {
                        level = minLevel;
                    }
                    result += settings.right[level];
                }
                else {
                    if (letter === '"') {
                        level = minLevel;
                    }
                    result += letter;
                }
            }
            return result;
        };
        Quote.prototype.getMaxLevel = function (text, leftQuote, rightQuote, length) {
            var count = this.count(text);
            return count[leftQuote] === count[rightQuote] ?
                length :
                Math.min(length, MAX_LEVEL_WITH_ERRORS);
        };
        return Quote;
    }());
    var quote = new Quote();
    var settings = {};
    getLocales().forEach(function (locale) {
        settings[locale] = deepCopy(getData(locale + '/quote'));
    });
    var quoteRule$1 = {
        name: 'common/punctuation/quote',
        handler: function (text, commonSettings, context) {
            var locale = context.prefs.locale[0];
            var settings = commonSettings[locale];
            if (!settings) {
                return text;
            }
            return quote.process({
                context: context,
                settings: settings,
                safeTags: this.safeTags,
            });
        },
        settings: settings,
    };

    var quoteLinkRule = {
        name: 'common/punctuation/quoteLink',
        queue: 'show-safe-tags-html',
        index: '+5',
        handler: function (text, _settings, context) {
            var quotes = this.getSetting('common/punctuation/quote', context.prefs.locale[0]);
            var lquote1 = htmlEntities.getByUtf(quotes.left[0]);
            var rquote1 = htmlEntities.getByUtf(quotes.right[0]);
            var lquote2 = htmlEntities.getByUtf(quotes.left[1]);
            var rquote2 = htmlEntities.getByUtf(quotes.right[1]);
            lquote2 = lquote2 ? ('|' + lquote2) : '';
            rquote2 = rquote2 ? ('|' + rquote2) : '';
            var re = new RegExp('(<[aA]\\s[^>]*?>)(' + lquote1 + lquote2 + ')([^]*?)(' + rquote1 + rquote2 + ')(</[aA]>)', 'g');
            return text.replace(re, '$2$1$3$5$4');
        },
    };

    Typograf.addRules([
        apostropheRule,
        delDoublePunctuationRule,
        hellipRule,
        quoteRule$1,
        quoteLinkRule,
    ]);

    var beforeBracketRule = {
        name: 'common/space/beforeBracket',
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var re = new RegExp('([' + char + '.!?,;…)])\\(', 'gi');
            return text.replace(re, '$1 (');
        },
    };

    var bracketRule$1 = {
        name: 'common/space/bracket',
        handler: function (text) {
            return text
                .replace(/(\() +/g, '(')
                .replace(/ +\)/g, ')');
        },
    };

    var delBeforePercentRule = {
        name: 'common/space/delBeforePercent',
        handler: function (text) {
            return text.replace(/(\d)( |\u00A0)(%|‰|‱)/g, '$1$3');
        },
    };

    var delBeforePunctuationRule = {
        name: 'common/space/delBeforePunctuation',
        handler: function (text) {
            return text.replace(/(^|[^!?:;,.…]) ([!?:;,])(?!\))/g, '$1$2');
        },
    };

    var delBetweenExclamationMarksRule = {
        name: 'common/space/delBetweenExclamationMarks',
        handler: function (text) {
            return text.replace(/([!?]) (?=[!?])/g, '$1');
        },
    };

    var delBeforeDotRule = {
        name: 'common/space/delBeforeDot',
        handler: function (text) {
            return text.replace(/(^|[^!?:;,.…]) (\.|\.\.\.)(\s|$)/g, '$1$2$3');
        },
    };

    var delLeadingBlanksRule = {
        name: 'common/space/delLeadingBlanks',
        handler: function (text) {
            return text.replace(/^[ \t]+/mg, '');
        },
        disabled: true,
    };

    var delRepeatNRule = {
        name: 'common/space/delRepeatN',
        index: '-1',
        handler: function (text, settings) {
            var maxConsecutiveLineBreaks = settings.maxConsecutiveLineBreaks;
            var consecutiveLineBreaksRegex = new RegExp("\n{".concat(maxConsecutiveLineBreaks + 1, ",}"), 'g');
            var replaceValue = repeat('\n', maxConsecutiveLineBreaks);
            return text.replace(consecutiveLineBreaksRegex, replaceValue);
        },
        settings: {
            maxConsecutiveLineBreaks: 2,
        },
    };

    var delRepeatSpaceRule = {
        name: 'common/space/delRepeatSpace',
        index: '-1',
        handler: function (text) {
            return text.replace(/([^\n \t])[ \t]{2,}(?![\n \t])/g, '$1 ');
        },
    };

    var delTrailingBlanksRule = {
        name: 'common/space/delTrailingBlanks',
        index: '-3',
        handler: function (text) {
            return text.replace(/[ \t]+\n/g, '\n');
        },
    };

    var insertFinalNewlineRule = {
        name: 'common/space/insertFinalNewline',
        queue: 'end',
        handler: function (text) {
            return text[text.length - 1] === '\n' ? text : text + '\n';
        },
        live: false,
        disabled: true,
    };

    var replaceTabRule = {
        name: 'common/space/replaceTab',
        index: '-5',
        handler: function (text) {
            return text.replace(/\t/g, '    ');
        },
    };

    var squareBracketRule = {
        name: 'common/space/squareBracket',
        handler: function (text) {
            return text
                .replace(/(\[) +/g, '[')
                .replace(/ +\]/g, ']');
        },
    };

    var trimLeftRule = {
        name: 'common/space/trimLeft',
        index: '-4',
        handler: String.prototype.trimLeft ?
            function (text) { return text.trimLeft(); } :
            /* istanbul ignore next */
            function (text) { return text.replace(/^[\s\uFEFF\xA0]+/g, ''); },
    };

    var trimRightRule = {
        name: 'common/space/trimRight',
        index: '-3',
        live: false,
        handler: String.prototype.trimRight ?
            function (text) { return text.trimRight(); } :
            /* istanbul ignore next */
            function (text) { return text.replace(/[\s\uFEFF\xA0]+$/g, ''); }
    };

    var reColon = new RegExp('(\\D):([^)",:.?\\s\\/\\\\' + privateLabel + '])', 'g');
    var afterColonRule = {
        name: 'common/space/afterColon',
        handler: function (text) {
            return text.replace(reColon, '$1: $2');
        },
    };

    var afterCommaRule = {
        name: 'common/space/afterComma',
        handler: function (text, settings, context) {
            var quote = context.getData('quote');
            var quotes = typeof quote === 'string' ? quote : quote.right;
            return text.replace(new RegExp('(.),([^)",:.?\\s\\/\\\\' + privateLabel + quotes + '])', 'g'), function ($0, $1, $2) { return isDigit($1) && isDigit($2) ? $0 : $1 + ', ' + $2; });
        }
    };

    var reQuestionMark = new RegExp('\\?([^).…!;?\\s[\\])' + privateLabel + getData('common/quote') + '])', 'g');
    var afterQuestionMarkRule = {
        name: 'common/space/afterQuestionMark',
        handler: function (text) {
            return text.replace(reQuestionMark, '? $1');
        },
    };

    var reExclamationMark = new RegExp('!([^).…!;?\\s[\\])' + privateLabel + getData('common/quote') + '])', 'g');
    var afterExclamationMarkRule = {
        name: 'common/space/afterExclamationMark',
        handler: function (text) {
            return text.replace(reExclamationMark, '! $1');
        },
    };

    var reSemicolon = new RegExp(';([^).…!;?\\s[\\])' + privateLabel + getData('common/quote') + '])', 'g');
    var afterSemicolonRule = {
        name: 'common/space/afterSemicolon',
        handler: function (text) {
            return text.replace(reSemicolon, '; $1');
        },
    };

    Typograf.addRules([
        afterColonRule,
        afterCommaRule,
        afterQuestionMarkRule,
        afterExclamationMarkRule,
        afterSemicolonRule,
        beforeBracketRule,
        bracketRule$1,
        delBeforeDotRule,
        delBeforePercentRule,
        delBeforePunctuationRule,
        delBetweenExclamationMarksRule,
        delLeadingBlanksRule,
        delRepeatNRule,
        delRepeatSpaceRule,
        delTrailingBlanksRule,
        insertFinalNewlineRule,
        replaceTabRule,
        squareBracketRule,
        trimLeftRule,
        trimRightRule,
    ]);

    var arrowRule = {
        name: 'common/symbols/arrow',
        handler: function (text) {
            return replace(text, [
                [/(^|[^-])->(?!>)/g, '$1→'],
                [/(^|[^<])<-(?!-)/g, '$1←']
            ]);
        },
    };

    var cfRule = {
        name: 'common/symbols/cf',
        handler: function (text) {
            var re = new RegExp('(^|[\\s(\\[+≈±−—–\\-])(\\d+(?:[.,]\\d+)?)[ \u00A0\u2009]?(C|F)([\\W\\s.,:!?")\\]]|$)', 'mg');
            return text.replace(re, '$1$2\u2009°$3$4');
        },
    };

    var copyRule = {
        name: 'common/symbols/copy',
        handler: function (text) {
            return replace(text, [
                [/\(r\)/gi, '®'],
                [/(copyright )?\((c|с)\)/gi, '©'],
                [/\(tm\)/gi, '™']
            ]);
        },
    };

    Typograf.addRules([
        arrowRule,
        cfRule,
        copyRule,
    ]);

    var mainRule$1 = {
        name: 'en-US/dash/main',
        index: '-5',
        handler: function (text) {
            var dashes = getData('common/dash');
            var nonBreakingSpace = '\u00A0';
            var emDash = '\u2014';
            var spaceBefore = "[ ".concat(nonBreakingSpace, "]"); // white space or a non-breaking space
            var spaceAfter = "[ ".concat(nonBreakingSpace, "\n]"); // same as spaceBefore, but includes line break
            var re = new RegExp("".concat(spaceBefore, "(").concat(dashes, ")(").concat(spaceAfter, ")"), 'g');
            return text.replace(re, "".concat(nonBreakingSpace).concat(emDash, "$2"));
        },
    };

    Typograf.addRules([
        mainRule$1,
    ]);

    var centuriesRule$1 = {
        name: 'ru/dash/centuries',
        handler: function (text, settings) {
            var dashes = '(' + getData('common/dash') + ')';
            var re = new RegExp('(X|I|V)[ |\u00A0]?' + dashes + '[ |\u00A0]?(X|I|V)', 'g');
            return text.replace(re, '$1' + settings.dash + '$3');
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var daysMonthRule = {
        name: 'ru/dash/daysMonth',
        handler: function (text, settings) {
            var re = new RegExp('(^|\\s)([123]?\\d)' +
                '(' + getData('common/dash') + ')' +
                '([123]?\\d)[ \u00A0]' +
                '(' + getData('ru/monthGenCase') + ')', 'g');
            return text.replace(re, '$1$2' + settings.dash + '$4\u00A0$5');
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var deRule = {
        name: 'ru/dash/de',
        handler: function (text) {
            var re = new RegExp('([a-яё]+) де' + getData('ru/dashAfterDe'), 'g');
            return text.replace(re, '$1-де');
        },
        disabled: true,
    };

    var decadeRule = {
        name: 'ru/dash/decade',
        handler: function (text, settings) {
            var re = new RegExp('(^|\\s)(\\d{3}|\\d)0' +
                '(' + getData('common/dash') + ')' +
                '(\\d{3}|\\d)0(-е[ \u00A0])' +
                '(?=г\\.?[ \u00A0]?г|год)', 'g');
            return text.replace(re, '$1$20' + settings.dash + '$40$5');
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var directSpeechRule = {
        name: 'ru/dash/directSpeech',
        handler: function (text) {
            var dashes = getData('common/dash');
            var re1 = new RegExp("([\"\u00BB\u2018\u201C,])[ |\u00A0]?(".concat(dashes, ")[ |\u00A0]"), 'g');
            var re2 = new RegExp("(^|".concat(privateLabel, ")(").concat(dashes, ")( |\u00A0)"), 'gm');
            var re3 = new RegExp("([.\u2026?!])[ \u00A0](".concat(dashes, ")[ \u00A0]"), 'g');
            return text
                .replace(re1, '$1\u00A0\u2014 ')
                .replace(re2, '$1\u2014\u00A0')
                .replace(re3, '$1 \u2014\u00A0');
        },
    };

    var izpodRule = {
        name: 'ru/dash/izpod',
        handler: function (text) {
            var re = new RegExp(getData('ru/dashBefore') + '(И|и)з под' + getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1$2з-под');
        },
    };

    var izzaRule = {
        name: 'ru/dash/izza',
        handler: function (text) {
            var re = new RegExp(getData('ru/dashBefore') + '(И|и)з за' + getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1$2з-за');
        },
    };

    var kaRule = {
        name: 'ru/dash/ka',
        handler: function (text) {
            var re = new RegExp('([a-яё]+) ка(сь)?' + getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1-ка$2');
        },
    };

    var koeRule = {
        name: 'ru/dash/koe',
        handler: function (text) {
            var re = new RegExp(getData('ru/dashBefore') +
                '([Кк]о[ей])\\s([а-яё]{3,})' +
                getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1$2-$3');
        },
    };

    var mainRule = {
        name: 'ru/dash/main',
        index: '-5',
        handler: function (text) {
            var dashes = getData('common/dash');
            var re = new RegExp('([ \u00A0])(' + dashes + ')([ \u00A0\\n])', 'g');
            return text.replace(re, '\u00A0\u2014$3');
        },
    };

    var monthRule = {
        name: 'ru/dash/month',
        handler: function (text, settings) {
            var months = '(' + getData('ru/month') + ')';
            var monthsPre = '(' + getData('ru/monthPreCase') + ')';
            var dashes = getData('common/dash');
            var re = new RegExp(months + ' ?(' + dashes + ') ?' + months, 'gi');
            var rePre = new RegExp(monthsPre + ' ?(' + dashes + ') ?' + monthsPre, 'gi');
            var newSubStr = '$1' + settings.dash + '$3';
            return text
                .replace(re, newSubStr)
                .replace(rePre, newSubStr);
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var surnameRule = {
        name: 'ru/dash/surname',
        handler: function (text) {
            var re = new RegExp('([А-ЯЁ][а-яё]+)\\s-([а-яё]{1,3})(?![^а-яё]|$)', 'g');
            return text.replace(re, '$1\u00A0\u2014$2');
        },
    };

    var takiRule = {
        name: 'ru/dash/taki',
        handler: function (text) {
            var re = new RegExp('(верно|довольно|опять|прямо|так|вс[её]|действительно|неужели)\\s(таки)' +
                getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1-$2');
        },
    };

    var timeRule = {
        name: 'ru/dash/time',
        handler: function (text, settings) {
            var re = new RegExp(getData('ru/dashBefore') +
                '(\\d?\\d:[0-5]\\d)' +
                getData('common/dash') +
                '(\\d?\\d:[0-5]\\d)' +
                getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1$2' + settings.dash + '$3');
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var toRule = {
        name: 'ru/dash/to',
        handler: function (text) {
            var words = '[Оо]ткуда|[Кк]уда|[Гг]де|[Кк]огда|[Зз]ачем|[Пп]очему|[Кк]ак|[Кк]ако[ейм]|[Кк]акая|[Кк]аки[емх]|[Кк]акими|[Кк]акую|[Чч]то|[Чч]его|[Чч]е[йм]|[Чч]ьим?|[Кк]то|[Кк]ого|[Кк]ому|[Кк]ем';
            var re = new RegExp('(^|[^А-ЯЁа-яё\\w])(' + words + ')( | -|- )(то|либо|нибудь)' +
                getData('ru/dashAfter'), 'g');
            return text.replace(re, function ($0, $1, $2, $3, $4) {
                var kakto = $2 + $3 + $4;
                // Отдельно обрабатываем в ru/dash/kakto
                if (kakto === 'как то' || kakto === 'Как то') {
                    return $0;
                }
                return $1 + $2 + '-' + $4;
            });
        },
    };

    var kaktoRule = {
        name: 'ru/dash/kakto',
        handler: function (text) {
            var re = new RegExp('(^|[^А-ЯЁа-яё\\w])([Кк]ак) то' + getData('ru/dashAfter'), 'g');
            return text.replace(re, '$1$2-то');
        },
    };

    var weekdayRule$1 = {
        name: 'ru/dash/weekday',
        handler: function (text, settings) {
            var part = '(' + getData('ru/weekday') + ')';
            var re = new RegExp(part + ' ?(' + getData('common/dash') + ') ?' + part, 'gi');
            return text.replace(re, '$1' + settings.dash + '$3');
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    var yearsRule$1 = {
        name: 'ru/dash/years',
        handler: function (text, settings) {
            var dashes = getData('common/dash');
            var re = new RegExp('(\\D|^)(\\d{4})[ \u00A0]?(' +
                dashes + ')[ \u00A0]?(\\d{4})(?=[ \u00A0]?г)', 'g');
            return text.replace(re, function ($0, $1, $2, $3, $4) {
                if (parseInt($2, 10) < parseInt($4, 10)) {
                    return $1 + $2 + settings.dash + $4;
                }
                return $0;
            });
        },
        settings: {
            dash: '\u2013', // &ndash;
        },
    };

    Typograf.addRules([
        centuriesRule$1,
        daysMonthRule,
        deRule,
        decadeRule,
        directSpeechRule,
        izpodRule,
        izzaRule,
        kaRule,
        koeRule,
        mainRule,
        monthRule,
        surnameRule,
        takiRule,
        timeRule,
        toRule,
        kaktoRule,
        weekdayRule$1,
        yearsRule$1,
    ]);

    var sp1 = '(-|\\.|\\/)';
    var sp2 = '(-|\\/)';
    var re1 = new RegExp('(^|\\D)(\\d{4})' + sp1 + '(\\d{2})' + sp1 + '(\\d{2})(\\D|$)', 'gi');
    var re2 = new RegExp('(^|\\D)(\\d{2})' + sp2 + '(\\d{2})' + sp2 + '(\\d{4})(\\D|$)', 'gi');
    var fromISORule = {
        name: 'ru/date/fromISO',
        handler: function (text) {
            return text
                .replace(re1, '$1$6.$4.$2$7')
                .replace(re2, '$1$4.$2.$6$7');
        },
    };

    var weekdayRule = {
        name: 'ru/date/weekday',
        handler: function (text) {
            var space = '( |\u00A0)';
            var monthCase = getData('ru/monthGenCase');
            var weekday = getData('ru/weekday');
            var re = new RegExp('(\\d)' + space + '(' + monthCase + '),' + space + '(' + weekday + ')', 'gi');
            return text.replace(re, function (_, $1, $2, $3, $4, $5) {
                return $1 + $2 + $3.toLowerCase() + ',' + $4 + $5.toLowerCase();
            });
        },
    };

    Typograf.addRules([
        fromISORule,
        weekdayRule,
    ]);

    var currencyRule = {
        name: 'ru/money/currency',
        handler: function (text) {
            var currency = '([$€¥Ұ£₤₽])';
            var space = '[ \u00A0\u2009\u202F]';
            var re1 = new RegExp('(^|[\\D]{2})' + currency + ' ?(' + regExpNumber + '(' + space + '\\d{3})*)(' + space + '?(тыс\\.|млн|млрд|трлн))?', 'gm');
            var re2 = new RegExp('(^|[\\D])(' + regExpNumber + ') ?' + currency, 'gm');
            return text
                .replace(re1, function ($0, $1, $2, $3, $4, $5, $6, $7) {
                return $1 + $3 + ($7 ? '\u00A0' + $7 : '') + '\u00A0' + $2;
            })
                .replace(re2, '$1$2\u00A0$4');
        },
        disabled: true,
    };

    var rubleRule = {
        name: 'ru/money/ruble',
        handler: function (text) {
            var newSubstr = '$1\u00A0₽';
            var commonPart = '(\\d+)( |\u00A0)?(р|руб)\\.';
            var re1 = new RegExp('^' + commonPart + '$', 'g');
            var re2 = new RegExp(commonPart + '(?=[!?,:;])', 'g');
            var re3 = new RegExp(commonPart + '(?=\\s+[A-ЯЁ])', 'g');
            return text
                .replace(re1, newSubstr)
                .replace(re2, newSubstr)
                .replace(re3, newSubstr + '.');
        },
        disabled: true,
    };

    Typograf.addRules([
        currencyRule,
        rubleRule,
    ]);

    function abbr($0, $1, $2, $3) {
        // дд.мм.гггг
        if ($2 === 'дд' && $3 === 'мм') {
            return $0;
        }
        // Являются ли сокращения ссылкой
        if (['рф', 'ру', 'рус', 'орг', 'укр', 'бг', 'срб'].indexOf($3) > -1) {
            return $0;
        }
        return $1 + $2 + '.' + '\u00A0' + $3 + '.';
    }
    var abbrRule = {
        name: 'ru/nbsp/abbr',
        handler: function (text) {
            var re = new RegExp("(^|\\s|".concat(privateLabel, ")([\u0430-\u044F\u0451]{1,3})\\. ?([\u0430-\u044F\u0451]{1,3})\\."), 'g');
            return text
                .replace(re, abbr)
                // Для тройных сокращений - а.е.м.
                .replace(re, abbr);
        },
    };

    var addrRule = {
        name: 'ru/nbsp/addr',
        handler: function (text) {
            return text
                .replace(/(\s|^)(дом|д\.|кв\.|под\.|п-д) *(\d+)/gi, '$1$2\u00A0$3')
                .replace(/(\s|^)(мкр-н|мк-н|мкр\.|мкрн)\s/gi, '$1$2\u00A0') // микрорайон
                .replace(/(\s|^)(эт\.) *(-?\d+)/gi, '$1$2\u00A0$3')
                .replace(/(\s|^)(\d+) +этаж([^а-яё]|$)/gi, '$1$2\u00A0этаж$3')
                .replace(/(\s|^)литер\s([А-Я]|$)/gi, '$1литер\u00A0$2')
                /*
                    область, край, станция, поселок, село,
                    деревня, улица, переулок, проезд, проспект,
                    бульвар, площадь, набережная, шоссе,
                    тупик, офис, комната, участок, владение, строение, корпус
                */
                .replace(/(\s|^)(обл|кр|ст|пос|с|д|ул|пер|пр|пр-т|просп|пл|бул|б-р|наб|ш|туп|оф|комн?|уч|вл|влад|стр|кор)\. *([а-яёa-z\d]+)/gi, '$1$2.\u00A0$3')
                // город
                .replace(/(\D[ \u00A0]|^)г\. ?([А-ЯЁ])/gm, '$1г.\u00A0$2');
        },
    };

    var afterNumberSignRule = {
        name: 'ru/nbsp/afterNumberSign',
        handler: function (text) {
            // \u2009 - THIN SPACE
            // \u202F - NARROW NO-BREAK SPACE
            return text.replace(/№[ \u00A0\u2009]?(\d|п\/п)/g, '№\u202F$1');
        },
    };

    var beforeParticleRule = {
        name: 'ru/nbsp/beforeParticle',
        index: '+5',
        handler: function (text) {
            var particles = '(ли|ль|же|ж|бы|б)';
            var re1 = new RegExp('([А-ЯЁа-яё]) ' + particles + '(?=[,;:?!"‘“»])', 'g');
            var re2 = new RegExp('([А-ЯЁа-яё])[ \u00A0]' + particles + '[ \u00A0]', 'g');
            return text
                .replace(re1, '$1\u00A0$2')
                .replace(re2, '$1\u00A0$2 ');
        },
    };

    var centuriesRule = {
        name: 'ru/nbsp/centuries',
        handler: function (text) {
            var dashes = getData('common/dash');
            var before = '(^|\\s)([VIX]+)';
            var after = '(?=[,;:?!"‘“»]|$)';
            var re1 = new RegExp(before + '[ \u00A0]?в\\.?' + after, 'gm');
            var re2 = new RegExp(before + '(' + dashes + ')' + '([VIX]+)[ \u00A0]?в\\.?([ \u00A0]?в\\.?)?' + after, 'gm');
            return text
                .replace(re1, '$1$2\u00A0в.')
                .replace(re2, '$1$2$3$4\u00A0вв.');
        },
    };

    var dayMonthRule = {
        name: 'ru/nbsp/dayMonth',
        handler: function (text) {
            var re = new RegExp('(\\d{1,2}) (' + getData('ru/shortMonth') + ')', 'gi');
            return text.replace(re, '$1\u00A0$2');
        },
    };

    var initialsRule = {
        name: 'ru/nbsp/initials',
        handler: function (text) {
            var spaces = '\u00A0\u202F '; // nbsp, thinsp
            var quote = getData('ru/quote');
            var re = new RegExp('(^|[(' + spaces +
                quote.left +
                privateLabel +
                '"])([А-ЯЁ])\\.[' + spaces + ']?([А-ЯЁ])\\.[' + spaces +
                ']?([А-ЯЁ][а-яё]+)', 'gm');
            return text.replace(re, '$1$2.\u00A0$3.\u00A0$4');
        },
    };

    var pow = {
        '2': '²',
        '²': '²',
        '3': '³',
        '³': '³',
        '': ''
    };
    var mRule = {
        name: 'ru/nbsp/m',
        index: '+5',
        handler: function (text) {
            var re = new RegExp('(^|[\\s,.\\(' + privateLabel + '])' +
                '(\\d+)[ \u00A0]?(мм?|см|км|дм|гм|mm?|km|cm|dm)([23²³])?([\\s\\).!?,;' +
                privateLabel + ']|$)', 'gm');
            return text.replace(re, function (_$0, $1, $2, $3, $4, $5) {
                return $1 + $2 + '\u00A0' + $3 + pow[$4 || ''] + ($5 === '\u00A0' ? ' ' : $5);
            });
        },
    };

    var mlnRule = {
        name: 'ru/nbsp/mln',
        handler: function (text) {
            return text.replace(/(\d) ?(тыс|млн|млрд|трлн)(\.|\s|$)/gi, '$1\u00a0$2$3');
        },
    };

    var oooRule = {
        name: 'ru/nbsp/ooo',
        handler: function (text) {
            return text.replace(/(^|[^a-яёA-ЯЁ])(ООО|ОАО|ЗАО|НИИ|ПБОЮЛ) /g, '$1$2\u00A0');
        },
    };

    var pageRule = {
        name: 'ru/nbsp/page',
        handler: function (text) {
            var re = new RegExp('(^|[)\\s' + privateLabel + '])' +
                '(стр|гл|рис|илл?|ст|п|c)\\. *(\\d+)([\\s.,?!;:]|$)', 'gim');
            return text.replace(re, '$1$2.\u00A0$3$4');
        },
    };

    var psRule = {
        name: 'ru/nbsp/ps',
        handler: function (text) {
            var re = new RegExp("(^|\\s|".concat(privateLabel, ")[p\u0437]\\.[ \u00A0]?([p\u0437]\\.[ \u00A0]?)?[s\u044B]\\.:? "), 'gim');
            return text.replace(re, function ($0, $1, $2) {
                return $1 + ($2 ? 'P.\u00A0P.\u00A0S. ' : 'P.\u00A0S. ');
            });
        },
    };

    var rubleKopekRule = {
        name: 'ru/nbsp/rubleKopek',
        handler: function (text) {
            return text.replace(/(\d) ?(?=(руб|коп)\.)/g, '$1\u00A0');
        },
    };

    var seeRule = {
        name: 'ru/nbsp/see',
        handler: function (text) {
            var re = new RegExp("(^|\\s|".concat(privateLabel, "|\\()(\u0441\u043C|\u0438\u043C)\\.[ \u00A0]?([\u0430-\u044F\u04510-9a-z]+)([\\s.,?!]|$)"), 'gi');
            return text.replace(re, function ($0, $1, $2, $3, $4) {
                return ($1 === '\u00A0' ? ' ' : $1) + $2 + '.\u00A0' + $3 + $4;
            });
        },
    };

    var yearRule$1 = {
        name: 'ru/nbsp/year',
        handler: function (text) {
            return text.replace(/(^|\D)(\d{4}) ?г([ ,;.\n]|$)/g, '$1$2\u00A0г$3');
        },
    };

    var yearsRule = {
        name: 'ru/nbsp/years',
        index: '+5',
        handler: function (text) {
            var dashes = getData('common/dash');
            var re = new RegExp('(^|\\D)(\\d{4})(' +
                dashes + ')(\\d{4})[ \u00A0]?г\\.?([ \u00A0]?г\\.)?(?=[,;:?!"‘“»\\s]|$)', 'gm');
            return text.replace(re, '$1$2$3$4\u00A0гг.');
        },
    };

    Typograf.addRules([
        abbrRule,
        addrRule,
        afterNumberSignRule,
        beforeParticleRule,
        centuriesRule,
        dayMonthRule,
        initialsRule,
        mRule,
        mlnRule,
        oooRule,
        pageRule,
        psRule,
        rubleKopekRule,
        seeRule,
        yearRule$1,
        yearsRule,
    ]);

    var commaRule$1 = {
        name: 'ru/number/comma',
        handler: function (text) {
            // \u00A0 - NO-BREAK SPACE
            // \u2009 - THIN SPACE
            // \u202F - NARROW NO-BREAK SPACE
            return text.replace(/(^|\s)(\d+)\.(\d+[\u00A0\u2009\u202F ]*?[%‰°×x])/gim, '$1$2,$3');
        },
    };

    var ordinalsRule = {
        name: 'ru/number/ordinals',
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var re = new RegExp('(\\d[%‰]?)-(ый|ой|ая|ое|ые|ым|ом|ых|ого|ому|ыми)(?![' + char + '])', 'g');
            return text.replace(re, function ($0, $1, $2) {
                var parts = {
                    'ой': 'й',
                    'ый': 'й',
                    'ая': 'я',
                    'ое': 'е',
                    'ые': 'е',
                    'ым': 'м',
                    'ом': 'м',
                    'ых': 'х',
                    'ого': 'го',
                    'ому': 'му',
                    'ыми': 'ми',
                };
                return $1 + '-' + parts[$2];
            });
        },
    };

    Typograf.addRules([
        commaRule$1,
        ordinalsRule,
    ]);

    function removeOptAlignTags(text, classNames) {
        var re = new RegExp('<span class="(' + classNames.join('|') + ')">([^]*?)</span>', 'g');
        return text.replace(re, '$2');
    }
    function removeOptAlignTagsFromTitle(text, classNames) {
        return text.replace(/<title>[^]*?<\/title>/i, function (text) {
            return removeOptAlignTags(text, classNames);
        });
    }

    var classNames$2 = [
        'typograf-oa-lbracket',
        'typograf-oa-n-lbracket',
        'typograf-oa-sp-lbracket'
    ];
    var name$2 = 'ru/optalign/bracket';
    var bracketRule = {
        name: name$2,
        handler: function (text) {
            return text
                .replace(/( |\u00A0)\(/g, '<span class="typograf-oa-sp-lbracket">$1</span><span class="typograf-oa-lbracket">(</span>')
                .replace(/^\(/gm, '<span class="typograf-oa-n-lbracket">(</span>');
        },
        disabled: true,
        htmlAttrs: false,
    };
    var innerStartBracketRule = {
        name: name$2,
        queue: 'start',
        handler: function (text) {
            return removeOptAlignTags(text, classNames$2);
        },
        htmlAttrs: false,
    };
    var innerEndBracketRule = {
        name: name$2,
        queue: 'end',
        handler: function (text) {
            return removeOptAlignTagsFromTitle(text, classNames$2);
        },
        htmlAttrs: false,
    };

    var classNames$1 = [
        'typograf-oa-comma',
        'typograf-oa-comma-sp',
    ];
    var name$1 = 'ru/optalign/comma';
    var commaRule = {
        name: name$1,
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var re = new RegExp('([' + char + '\\d\u0301]+), ', 'gi');
            return text.replace(re, '$1<span class="typograf-oa-comma">,</span><span class="typograf-oa-comma-sp"> </span>');
        },
        disabled: true,
        htmlAttrs: false,
    };
    var innerStartCommaRule = {
        name: name$1,
        queue: 'start',
        handler: function (text) {
            return removeOptAlignTags(text, classNames$1);
        },
        htmlAttrs: false,
    };
    var innerEndCommaRule = {
        name: name$1,
        queue: 'end',
        handler: function (text) {
            return removeOptAlignTagsFromTitle(text, classNames$1);
        },
        htmlAttrs: false,
    };

    var classNames = [
        'typograf-oa-lquote',
        'typograf-oa-n-lquote',
        'typograf-oa-sp-lquote'
    ];
    var name = 'ru/optalign/quote';
    var quoteRule = {
        name: name,
        handler: function (text) {
            var quote = this.getSetting('common/punctuation/quote', 'ru');
            var lquotes = '([' + quote.left[0] + (quote.left[1] || '') + '])';
            var reNewLine = new RegExp('(^|\n\n|' + privateLabel + ')(' + lquotes + ')', 'g');
            var reInside = new RegExp('([^\n' + privateLabel + '])([ \u00A0\n])(' + lquotes + ')', 'gi');
            return text
                .replace(reNewLine, '$1<span class="typograf-oa-n-lquote">$2</span>')
                .replace(reInside, '$1<span class="typograf-oa-sp-lquote">$2</span><span class="typograf-oa-lquote">$3</span>');
        },
        disabled: true,
        htmlAttrs: false,
    };
    var innerStartQuoteRule = {
        name: name,
        queue: 'start',
        handler: function (text) {
            return removeOptAlignTags(text, classNames);
        },
        htmlAttrs: false,
    };
    var innerEndQuoteRule = {
        name: name,
        queue: 'end',
        handler: function (text) {
            return removeOptAlignTagsFromTitle(text, classNames);
        },
        htmlAttrs: false,
    };

    Typograf.addRules([
        bracketRule,
        commaRule,
        quoteRule,
    ]);
    Typograf.addInnerRules([
        innerStartBracketRule,
        innerEndBracketRule,
        innerStartCommaRule,
        innerEndCommaRule,
        innerStartQuoteRule,
        innerEndQuoteRule,
    ]);

    var accentRule = {
        name: 'ru/other/accent',
        handler: function (text) {
            return text.replace(/([а-яё])([АЕЁИОУЫЭЮЯ])([^А-ЯЁ\w]|$)/g, function ($0, $1, $2, $3) {
                return $1 + $2.toLowerCase() + '\u0301' + $3;
            });
        },
        disabled: true,
    };

    var defaultCityCodeLength = 5;
    var countryCode = '7';
    var exceptions = [];
    var exceptionsMax = 8;
    var exceptionsMin = 2;
    [
        4162, 416332, 8512, 851111, 4722, 4725, 391379, 8442, 4732,
        4152, 4154451, 4154459, 4154455, 41544513, 8142, 8332, 8612,
        8622, 3525, 812, 8342, 8152, 3812, 4862, 3422, 342633, 8112,
        9142, 8452, 3432, 3434, 3435, 4812, 8432, 8439, 3822,
        4872, 3412, 3511, 3512, 3022, 4112, 4852, 4855, 3852, 3854,
        8182, 818, 90, 3472, 4741, 4764, 4832, 4922, 8172, 8202, 8722,
        4932, 493, 3952, 3951, 3953, 411533, 4842, 3842, 3843, 8212,
        4942, '39131-39179', '39190-39199', 391, 4712, 4742, 8362, 495, 499, 4966, 4964, 4967, 498,
        8312, 8313, 3832, 383612, 3532, 8412, 4232, 423370, 423630, 8632,
        8642, 8482, 4242, 8672, 8652, 4752, 4822, 482502, 4826300, 3452,
        8422, 4212, 3466, 3462, 8712, 8352,
        '901-934', '936-939', '950-953', 958, '960-969',
        '977-989', '991-997', 999
    ].forEach(function (num) {
        if (typeof num === 'string') {
            var buf = num.split('-');
            for (var i = +buf[0]; i <= +buf[1]; i++) {
                exceptions.push(i);
            }
        }
        else {
            exceptions.push(num);
        }
    });
    function phone(num) {
        var firstSym = num[0];
        var cityCode = '';
        var hasPlusWithCode;
        var hasEight;
        if (num.length < 8) {
            return phoneBlocks(num);
        }
        // 8 495 123-45-67, +7 495 123-45-67
        if (num.length > 10) {
            if (firstSym === '+') {
                if (num[1] === countryCode) {
                    hasPlusWithCode = true;
                    num = num.substr(2);
                }
                else {
                    return num;
                }
            }
            else if (firstSym === '8') {
                hasEight = true;
                num = num.substr(1);
            }
        }
        for (var cityCodeLen = exceptionsMax; cityCodeLen >= exceptionsMin; cityCodeLen--) {
            var code = +num.substr(0, cityCodeLen);
            if (exceptions.indexOf(code) > -1) {
                cityCode = num.substr(0, cityCodeLen);
                num = num.substr(cityCodeLen);
                break;
            }
        }
        if (!cityCode) {
            cityCode = num.substr(0, defaultCityCodeLength);
            num = num.substr(defaultCityCodeLength);
        }
        return (hasPlusWithCode ? '+' + countryCode + '\u00A0' : '') +
            (hasEight ? '8\u00A0' : '') +
            prepareCode(cityCode) + '\u00A0' +
            phoneBlocks(num);
    }
    function prepareCode(code) {
        var numCode = +code;
        var len = code.length;
        var result = [code];
        var withoutBrackets = false;
        if (len > 3) {
            switch (len) {
                case 4:
                    result = [code.substr(0, 2), code.substr(2, 2)];
                    break;
                case 5:
                    result = [code.substr(0, 3), code.substr(3, 3)];
                    break;
                case 6:
                    result = [code.substr(0, 2), code.substr(2, 2), code.substr(4, 2)];
                    break;
            }
        }
        else {
            // Мобильные и московские номера без скобок
            withoutBrackets = (numCode > 900 && numCode <= 999) || numCode === 495 || numCode === 499;
        }
        var str = result.join('-');
        return withoutBrackets ? str : '(' + str + ')';
    }
    function phoneBlocks(num) {
        var add = '';
        if (num.length % 2) {
            add = num[0];
            add += num.length <= 5 ? '-' : '';
            num = num.substr(1, num.length - 1);
        }
        return add + num.split(/(?=(?:\d\d)+$)/).join('-');
    }
    function clearPhone(text) {
        return text.replace(/[^\d+]/g, '');
    }
    var phoneNumberRule = {
        name: 'ru/other/phone-number',
        live: false,
        handler: function (text) {
            var re = new RegExp('(^|,| |' + privateLabel + ')(\\+7[\\d\\(\\) \u00A0-]{10,18})(?=,|;|' + privateLabel + '|$)', 'gm');
            return text
                .replace(re, function ($0, $1, $2) {
                var buf = clearPhone($2);
                return buf.length === 12 ? $1 + phone(buf) : $0;
            })
                .replace(
            // eslint-disable-next-line no-misleading-character-class
            /(^|[^а-яё])([☎☏✆📠📞📱]|т\.|тел\.|ф\.|моб\.|факс|сотовый|мобильный|телефон)(:?\s*?)([+\d(][\d \u00A0\-()]{3,}\d)/gi, function ($0, $1, $2, $3, $4) {
                var buf = clearPhone($4);
                if (buf.length >= 5) {
                    return $1 + $2 + $3 + phone(buf);
                }
                return $0;
            });
        },
    };

    Typograf.addRules([
        accentRule,
        phoneNumberRule,
    ]);

    var anoRule = {
        name: 'ru/punctuation/ano',
        handler: function (text) {
            var parts = [
                '([^«„[(!?,:;\\-‒–—\\s' + privateLabel + '])', // Запятую не ставим, если уже есть какой-либо знак
                '(?<!([^а-яА-Я]+ну|Ну))', // Запятую не ставим перед ну
                '(\\s+)', // Отступ между левой и правой частями в виде пробельных символов
                '(а|но)', // Союзы
                '(?= |\u00A0|\\n)' // Остальная часть предложения(пробел, неразрывной пробел, перевод строки)
            ];
            var re = new RegExp(parts.join(''), 'g');
            return text.replace(re, '$1,$3$4');
        },
    };

    var exclamationRule = {
        name: 'ru/punctuation/exclamation',
        handler: function (text) {
            return text
                .replace(/(^|[^!])!{2}($|[^!])/gm, '$1!$2')
                .replace(/(^|[^!])!{4}($|[^!])/gm, '$1!!!$2');
        },
        live: false,
    };

    var exclamationQuestionRule = {
        name: 'ru/punctuation/exclamationQuestion',
        index: '+5',
        handler: function (text) {
            var re = new RegExp('(^|[^!])!\\?([^?]|$)', 'g');
            return text.replace(re, '$1?!$2');
        },
    };

    var hellipQuestionRule = {
        name: 'ru/punctuation/hellipQuestion',
        handler: function (text) {
            return text
                .replace(/(^|[^.])(\.\.\.|…),/g, '$1…')
                .replace(/(!|\?)(\.\.\.|…)(?=[^.]|$)/g, '$1..');
        },
    };

    Typograf.addRules([
        anoRule,
        exclamationRule,
        exclamationQuestionRule,
        hellipQuestionRule,
    ]);

    var afterHellipRule = {
        name: 'ru/space/afterHellip',
        handler: function (text) {
            return text
                .replace(/([а-яё])(\.\.\.|…)([А-ЯЁ])/g, '$1$2 $3')
                .replace(/([?!]\.\.)([а-яёa-z])/gi, '$1 $2');
        },
    };

    var yearRule = {
        name: 'ru/space/year',
        handler: function (text, _settings, context) {
            var char = context.getData('char');
            var re = new RegExp('(^| |\u00A0)(\\d{3,4})(год([ауе]|ом)?)([^' +
                char + ']|$)', 'g');
            return text.replace(re, '$1$2 $3$5');
        }
    };

    Typograf.addRules([
        afterHellipRule,
        yearRule,
    ]);

    var nnRule = {
        name: 'ru/symbols/NN',
        handler: function (text) {
            return text.replace(/№№/g, '№');
        },
    };

    Typograf.addRules([
        nnRule,
    ]);

    var replacements = {
        A: 'А', // Latin: Russian
        a: 'а',
        B: 'В',
        E: 'Е',
        e: 'е',
        K: 'К',
        M: 'М',
        H: 'Н',
        O: 'О',
        o: 'о',
        P: 'Р',
        p: 'р',
        C: 'С',
        c: 'с',
        T: 'Т',
        y: 'у',
        X: 'Х',
        x: 'х'
    };
    var keys = Object.keys(replacements).join('');
    var switchingKeyboardLayoutRule = {
        name: 'ru/typo/switchingKeyboardLayout',
        handler: function (text) {
            var re = new RegExp('([' + keys + ']{1,3})(?=[А-ЯЁа-яё]+?)', 'g');
            return text.replace(re, function (str, $1) {
                var result = '';
                for (var i = 0; i < $1.length; i++) {
                    result += replacements[$1[i]];
                }
                return result;
            });
        }
    };

    Typograf.addRules([
        switchingKeyboardLayoutRule,
    ]);

    return Typograf;

}));

},{}]},{},[1])

//# sourceMappingURL=app.bundle.js.map
;
