{"version":3,"file":"js/ng.js","mappings":"uBAAAA,EAAOC,QAAU,i9F,YCAjBD,EAAOC,QAAU,+8E,YCAjBD,EAAOC,QAAU,6c,YCAjBD,EAAOC,QAAU,qvE,YCAjBD,EAAOC,QAAU,uxO,YCAjBD,EAAOC,QAAU,0xX,YCAjBD,EAAOC,QAAU,kmL,UCAjBD,EAAOC,QAAU,omD,YCAjBD,EAAOC,QAAU,y7B,YCAjBD,EAAOC,QAAU,ylD,YCAjBD,EAAOC,QAAU,glC,YCAjBD,EAAOC,QAAU,uvQ,YCAjBD,EAAOC,QAAU,y6G,YCAjBD,EAAOC,QAAU,gqK,YCAjBD,EAAOC,QAAU,wgoB,YCAjBD,EAAOC,QAAU,0hB,YCAjBD,EAAOC,QAAU,i5B,YCAjBD,EAAOC,QAAU,kzG,WCAjBD,EAAOC,QAAU,omU,YCAjBD,EAAOC,QAAU,mT,YCAjBD,EAAOC,QAAU,2jB,YCAjBD,EAAOC,QAAU,uiD,YCAjBD,EAAOC,QAAU,gtB,YCAjBD,EAAOC,QAAU,m5E,YCAjBD,EAAOC,QAAU,ikE,YCAjBD,EAAOC,QAAU,gr7J,YCAjBD,EAAOC,QAAU,ikE,YCAjBD,EAAOC,QAAU,45O,YCAjBD,EAAOC,QAAU,6kD,YCAjBD,EAAOC,QAAU,g8vB,YCAjBD,EAAOC,QAAU,+4yB,WCAjBD,EAAOC,QAAU,+0xB,WCIjBD,EAAOC,QAAU,SAASC,GACzB,SAASC,EAAIC,GACQ,oBAAZC,UACJA,QAAQD,OAASC,QAAQF,KAAK,kBAAmBC,EACtD,CAOA,IAC2B,oBAAfE,YAJmB,oBAAhBC,aAA2D,oBAArBC,iBAKnDF,WAAWJ,GACe,oBAATO,KACjBA,KAAKC,KAAK,KAAMR,GAEhBC,EAAI,wCAIN,CAFE,MAAOC,GACRD,EAAIC,EACL,CACD,C,kBC1BA,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,iBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,iBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,iBCApG,EAAQ,KAAR,CAA4F,EAAQ,K,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,iBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,M,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,gBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,kBCApG,EAAQ,KAAR,CAA4F,EAAQ,O,iBCApG,EAAQ,KAAR,CAA4F,EAAQ,M,GCChGO,EAA2B,CAAC,EAGhC,SAASC,EAAoBC,GAE5B,IAAIC,EAAeH,EAAyBE,GAC5C,QAAqBE,IAAjBD,EACH,OAAOA,EAAab,QAGrB,IAAID,EAASW,EAAyBE,GAAY,CAGjDZ,QAAS,CAAC,GAOX,OAHAe,EAAoBH,GAAUb,EAAQA,EAAOC,QAASW,GAG/CZ,EAAOC,OACf,CCrBAW,EAAoBK,EAAKjB,IACxB,IAAIkB,EAASlB,GAAUA,EAAOmB,WAC7B,IAAOnB,EAAiB,QACxB,IAAM,EAEP,OADAY,EAAoBQ,EAAEF,EAAQ,CAAEG,EAAGH,IAC5BA,CAAM,ECLdN,EAAoBQ,EAAI,CAACnB,EAASqB,KACjC,IAAI,IAAIC,KAAOD,EACXV,EAAoBY,EAAEF,EAAYC,KAASX,EAAoBY,EAAEvB,EAASsB,IAC5EE,OAAOC,eAAezB,EAASsB,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,IAE1E,ECNDX,EAAoBY,EAAI,CAACK,EAAKC,IAAUL,OAAOM,UAAUC,eAAetB,KAAKmB,EAAKC,G","sources":["webpack://renewi-site/./src/js/ng/app.js","webpack://renewi-site/./src/js/ng/controllers/audiencePopupController.js","webpack://renewi-site/./src/js/ng/controllers/bannerController.js","webpack://renewi-site/./src/js/ng/controllers/branchController.js","webpack://renewi-site/./src/js/ng/controllers/cartController.js","webpack://renewi-site/./src/js/ng/controllers/catalogController.js","webpack://renewi-site/./src/js/ng/controllers/checkoutFlowController.js","webpack://renewi-site/./src/js/ng/controllers/crosssellController.js","webpack://renewi-site/./src/js/ng/controllers/languageSwitchController.js","webpack://renewi-site/./src/js/ng/controllers/miniCartController.js","webpack://renewi-site/./src/js/ng/controllers/productBundleFormController.js","webpack://renewi-site/./src/js/ng/controllers/productFormController.js","webpack://renewi-site/./src/js/ng/controllers/searchController.js","webpack://renewi-site/./src/js/ng/controllers/upsellController.js","webpack://renewi-site/./src/js/ng/controllers/wizardController.js","webpack://renewi-site/./src/js/ng/controllers/zipcodeController.js","webpack://renewi-site/./src/js/ng/directive/addToCartButton.js","webpack://renewi-site/./src/js/ng/directive/datePicker.js","webpack://renewi-site/./src/js/ng/directive/easyPieChart.js","webpack://renewi-site/./src/js/ng/directive/fallbacksrc.js","webpack://renewi-site/./src/js/ng/directive/lightCase.js","webpack://renewi-site/./src/js/ng/directive/quantityInput.js","webpack://renewi-site/./src/js/ng/directive/toolTipster.js","webpack://renewi-site/./src/js/ng/services/chartService.js","webpack://renewi-site/./src/js/ng/services/globalService.js","webpack://renewi-site/./vendor/ng/angular-animate.js","webpack://renewi-site/./vendor/ng/angular-cookies.min.js","webpack://renewi-site/./vendor/ng/angular-sanitize.min.js","webpack://renewi-site/./vendor/ng/ngStorage.min.js","webpack://renewi-site/./vendor/ng/xeditable.min.js","webpack://renewi-site/../node_modules/ng-mask/dist/ngMask.js","webpack://renewi-site/../node_modules/zebra_datepicker/public/javascript/zebra_datepicker.js","webpack://renewi-site/../node_modules/script-loader/addScript.js","webpack://renewi-site/./src/js/ng/app.js?ba01","webpack://renewi-site/./src/js/ng/controllers/audiencePopupController.js?6fd0","webpack://renewi-site/./src/js/ng/controllers/bannerController.js?c090","webpack://renewi-site/./src/js/ng/controllers/branchController.js?d157","webpack://renewi-site/./src/js/ng/controllers/cartController.js?f55b","webpack://renewi-site/./src/js/ng/controllers/catalogController.js?5102","webpack://renewi-site/./src/js/ng/controllers/checkoutFlowController.js?05a1","webpack://renewi-site/./src/js/ng/controllers/crosssellController.js?10cb","webpack://renewi-site/./src/js/ng/controllers/languageSwitchController.js?baee","webpack://renewi-site/./src/js/ng/controllers/miniCartController.js?9ef5","webpack://renewi-site/./src/js/ng/controllers/productBundleFormController.js?ead8","webpack://renewi-site/./src/js/ng/controllers/productFormController.js?f7e8","webpack://renewi-site/./src/js/ng/controllers/searchController.js?1131","webpack://renewi-site/./src/js/ng/controllers/upsellController.js?2864","webpack://renewi-site/./src/js/ng/controllers/wizardController.js?c13e","webpack://renewi-site/./src/js/ng/controllers/zipcodeController.js?1d30","webpack://renewi-site/./src/js/ng/directive/addToCartButton.js?e263","webpack://renewi-site/./src/js/ng/directive/datePicker.js?228c","webpack://renewi-site/./src/js/ng/directive/easyPieChart.js?63d8","webpack://renewi-site/./src/js/ng/directive/fallbacksrc.js?b23c","webpack://renewi-site/./src/js/ng/directive/lightCase.js?cfdc","webpack://renewi-site/./src/js/ng/directive/quantityInput.js?dc73","webpack://renewi-site/./src/js/ng/directive/toolTipster.js?c650","webpack://renewi-site/./src/js/ng/services/chartService.js?f521","webpack://renewi-site/./src/js/ng/services/globalService.js?3bbc","webpack://renewi-site/./vendor/ng/angular-animate.js?5408","webpack://renewi-site/./vendor/ng/angular-cookies.min.js?5222","webpack://renewi-site/./vendor/ng/angular-sanitize.min.js?d9fb","webpack://renewi-site/./vendor/ng/ngStorage.min.js?85f4","webpack://renewi-site/./vendor/ng/xeditable.min.js?74b0","webpack://renewi-site/../node_modules/ng-mask/dist/ngMask.js?8275","webpack://renewi-site/../node_modules/zebra_datepicker/public/javascript/zebra_datepicker.js?7854","webpack://renewi-site/webpack/bootstrap","webpack://renewi-site/webpack/runtime/compat get default export","webpack://renewi-site/webpack/runtime/define property getters","webpack://renewi-site/webpack/runtime/hasOwnProperty shorthand"],"sourcesContent":["module.exports = \"// Add XSRF token to every header (Must be removed when switched to angular services calls)\\n$.ajaxSetup({\\n beforeSend: function (xhr) {\\n xhr.setRequestHeader(\\\"X-XSRF-Token\\\", $('input[name=__RequestVerificationToken]').val());\\n }\\n});\\nangular.module('audiencePopup', []);\\nangular.module('banner', []);\\nangular.module('branch', []);\\nangular.module('cart', []);\\nangular.module('catalog', []);\\nangular.module('checkoutFlow', []);\\nangular.module('crossSell', []);\\nangular.module('languageSwitch', []);\\nangular.module('miniCart', []);\\nangular.module('productForm', []);\\nangular.module('productBundleForm', []);\\nangular.module('upsell', []);\\nangular.module('upsellBanner', []);\\nangular.module('wizard', []);\\nangular.module('search', []);\\nangular.module(\\\"zipcode\\\", []);\\nangular.module('shopApp', ['audiencePopup', 'banner', 'branch', 'cart', 'catalog', 'checkoutFlow', 'crossSell', 'languageSwitch', 'miniCart', 'ngStorage', 'ngSanitize', 'ngCookies', 'ngAnimate', 'ngMask', 'productForm', 'productBundleForm', 'xeditable', 'upsell', 'upsellBanner', 'wizard', 'search', 'zipcode']).filter('to_trusted', ['$sce', function ($sce) {\\n return function (text) {\\n return $sce.trustAsHtml(text);\\n };\\n}]).config(['$cookiesProvider', function ($cookiesProvider) {\\n // Set $cookies defaults\\n $cookiesProvider.defaults.path = '/';\\n $cookiesProvider.defaults.secure = true;\\n}]).run(['$rootScope', '$http', function ($rootScope, $http) {\\n $http.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';\\n\\n if (document.getElementsByName(\\\"__RequestVerificationToken\\\").length > 0) {\\n $http.defaults.headers.common['X-XSRF-Token'] = document.getElementsByName(\\\"__RequestVerificationToken\\\")[0].value;\\n }\\n\\n $http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';\\n\\n $http.defaults.transformRequest = function (obj) {\\n return $.param(obj);\\n };\\n /*\\r\\n * Handle datalayer\\r\\n * @param {Array} products - Array of products\\r\\n * @param {String} googleAnalyticsListName\\r\\n * @param {Int} startFrom - Return products from this index on\\r\\n */\\n\\n\\n $rootScope.handleDataLayer = function (products, googleAnalyticsListName, startFrom, event) {\\n startFrom = startFrom ? startFrom : '0'; // Loop through products array and return only the products starting from the `startFrom` index\\n\\n const datalayerProducts = products.reduce(function (result, product, index) {\\n if (index >= startFrom && product.AnalyticsProductImpressionModel) {\\n product.AnalyticsProductImpressionModel.position = index + 1;\\n product.AnalyticsProductImpressionModel.list = googleAnalyticsListName;\\n result.push(product.AnalyticsProductImpressionModel);\\n }\\n\\n return result;\\n }, []); // Update datalayer\\n\\n window.dataLayerHelpers.updateProductList(datalayerProducts, event);\\n };\\n}]);\\nangular.element(document).ready(function () {\\n $('html').removeClass('angular--wait').addClass('angular--loaded');\\n});\"","module.exports = \"angular.module('audiencePopup').controller('AudiencePopupController', ['$scope', '$cookies', 'GlobalService', function ($scope, $cookies, GlobalService) {\\n var audiencePopup = this;\\n $scope.validZipCode = false;\\n $scope.showPopup = false;\\n\\n audiencePopup.openPopup = function () {\\n var body = angular.element(\\\"body\\\");\\n body.addClass(\\\"overlay-open\\\");\\n var html = angular.element(\\\"html\\\");\\n html.css(\\\"overflow-y\\\", \\\"hidden\\\");\\n };\\n\\n audiencePopup.closePopup = function () {\\n var body = angular.element(\\\"body\\\");\\n body.removeClass(\\\"overlay-open\\\");\\n var html = angular.element(\\\"html\\\");\\n html.css(\\\"overflow-y\\\", \\\"visible\\\");\\n $scope.showPopup = false;\\n };\\n\\n audiencePopup.setToggleEvent = function () {\\n window.addEventListener(\\\"openZipCodePopup\\\", e => {\\n if (e.detail) {\\n $scope.zipCode = e.detail;\\n }\\n\\n audiencePopup.validateZipCode();\\n audiencePopup.openPopup();\\n $scope.showPopup = true;\\n });\\n };\\n\\n audiencePopup.validateZipCode = function () {\\n if ($scope.zipCode.length < $scope.zipCodeLength) return $scope.validZipCode = false;\\n $scope.isLoading = true;\\n GlobalService.postData({\\n scController: 'Catalog',\\n scAction: 'ValidateZipCode',\\n zipCode: $scope.zipCode\\n }).success(function (data) {\\n $scope.validZipCode = data;\\n $scope.isLoading = false;\\n }).error(function (data) {\\n $scope.validZipCode = false;\\n $scope.isLoading = false;\\n });\\n };\\n\\n audiencePopup.setTargetAudience = function (isBusiness) {\\n $cookies.put('isBusiness', isBusiness, {\\n expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1))\\n }); // Set 'isBusiness' cookie\\n\\n $cookies.put('ExplicitAudience', true, {\\n expires: new Date(new Date().setFullYear(new Date().getFullYear() + 1))\\n }); // Set 'ExplicitAudience' cookie\\n\\n audiencePopup.storeZipCode();\\n window.location = $scope.baseUrl + '?business=' + isBusiness; // Redirect to alternative URL\\n };\\n\\n audiencePopup.reload = function () {\\n audiencePopup.storeZipCode();\\n $cookies.remove('city');\\n window.location.reload();\\n };\\n\\n audiencePopup.storeZipCode = function () {\\n if ($scope.validZipCode && $scope.zipCode.length >= $scope.zipCodeLength) {\\n $cookies.put(\\\"zipCode\\\", $scope.zipCode.toUpperCase(), {\\n expires: new Date(new Date().setDate(new Date().getDate() + 2))\\n });\\n }\\n };\\n}]);\"","module.exports = \"angular.module('banner').controller('BannerController', ['$rootScope', '$scope', 'GlobalService', function ($rootScope, $scope, GlobalService) {\\n $scope.scrollToLabel = function (label) {\\n GlobalService.scrollTo(label);\\n };\\n\\n $scope.initBanner = function (data) {\\n $scope.messages = data;\\n };\\n\\n $rootScope.$on('BANNER_UPDATE', function (event, data) {\\n if (data && !_.isEmpty(data)) {\\n $scope.messages = data;\\n }\\n });\\n}]);\"","module.exports = \"angular.module('branch').controller('BranchController', ['$scope', '$cookies', '$timeout', 'GlobalService', function ($scope, $cookies, $timeout, GlobalService) {\\n var BranchesCookieObj = $cookies.getObject('SelectedBranches');\\n var updateBranchTimer;\\n $scope.Branches = {};\\n\\n $scope.initSortByBranches = function (data) {\\n $scope.Branches.Branch = data.Branches;\\n $scope.Branches.SubBranch = data.SubBranches;\\n $scope.Branches.SelectedBranch = BranchesCookieObj ? getBranchById($scope.Branches.Branch, BranchesCookieObj.BranchId) : null;\\n $scope.Branches.SelectedSubBranch = BranchesCookieObj ? getBranchById($scope.Branches.SubBranch, BranchesCookieObj.SubBranchId) : null;\\n };\\n\\n $scope.updateBranchSelect = function () {\\n if (!$scope.Branches.SelectedBranch) $scope.Branches.SelectedSubBranch = null;\\n $timeout.cancel(updateBranchTimer);\\n updateBranchTimer = $timeout(function () {\\n var branchId = $scope.Branches.SelectedBranch ? $scope.Branches.SelectedBranch.Value : null;\\n var subBranchId = $scope.Branches.SelectedSubBranch ? $scope.Branches.SelectedSubBranch.Value : null;\\n var cookieValue = {\\n BranchId: branchId,\\n SubBranchId: subBranchId\\n };\\n var expireDate = new Date();\\n expireDate.setDate(expireDate.getDate() + 14);\\n $cookies.putObject('SelectedBranches', cookieValue, {\\n 'expires': expireDate,\\n 'path': '/'\\n });\\n $scope.$emit('BRANCH_UPDATE', cookieValue);\\n addEventToDataLayer($scope.Branches.SelectedBranch?.Name, $scope.Branches.SelectedSubBranch?.Name);\\n }, 200);\\n };\\n\\n function getBranchById(branchArray, branchId) {\\n var branchValue = _.find(branchArray, function (Branch) {\\n return Branch.Value == branchId;\\n });\\n\\n return branchValue || null;\\n }\\n\\n function addEventToDataLayer(branch, subBranch) {\\n dataLayer.push({\\n event: 'refineIndustry',\\n eventName: 'refine_industry',\\n branche_action: branch ? 'branche_verfijn' : 'branche_reset',\\n branche_name: branch,\\n sub_branche_name: subBranch,\\n eventCategory: 'Branche',\\n eventAction: branch ? 'verfijn' : 'reset',\\n eventLabel: branch ? `${branch}/${subBranch ?? branch}` : undefined\\n });\\n }\\n}]);\"","module.exports = \"angular.module('cart').controller('CartController', ['$rootScope', '$scope', '$sessionStorage', '$timeout', 'GlobalService', function ($rootScope, $scope, $sessionStorage, $timeout, GlobalService) {\\n $scope.$storage = $sessionStorage;\\n $scope.submitting = false;\\n $scope.$on('CART_UPDATE', function (event, data) {\\n $scope.getCartOverview($scope.currentPage);\\n });\\n /**\\r\\n * Scroll to the validation error element\\r\\n */\\n\\n function scrollToValidationError() {\\n GlobalService.scrollTo('.input-validation-error');\\n }\\n /*\\r\\n // TODO DELETE?\\r\\n angular.element(document).ready(function () {\\r\\n if ($rootScope.isInitialized == undefined) {\\r\\n $scope.ensureNumberOfProducts();\\r\\n $rootScope.isInitialized = true;\\r\\n }\\r\\n });*/\\n\\n\\n function checkPlacementDate(cartLine) {\\n if (!cartLine.IsValidPlacementDate || !cartLine.IsValidPickupDate) {\\n $timeout(function () {\\n angular.element('[name=\\\"cart.editableForm[' + cartLine.Id + ']\\\"].change').triggerHandler('click');\\n });\\n }\\n }\\n\\n $scope.getCartOverview = function () {\\n $scope.loading = true;\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'GetShoppingCartOverview'\\n }).success(function (data) {\\n $scope.loading = false;\\n\\n if (data !== undefined && data.Order.OrderLines !== undefined) {\\n _.each(data.Order.OrderLines, checkPlacementDate);\\n\\n $scope.cartOverview = data.Order;\\n $scope.productsInCartOverview = data.Order.OrderLines.length;\\n }\\n });\\n };\\n\\n $scope.ensureNumberOfProducts = function () {\\n if ($sessionStorage.NumberOfProducts == undefined) {\\n $scope.updateMiniCart();\\n }\\n };\\n\\n $scope.updateMiniCart = function () {\\n $rootScope.$broadcast('MINICART_UPDATE', '');\\n };\\n\\n $scope.addConditionalProduct = function (sku) {\\n $scope.conditionalProducts.push(sku);\\n };\\n\\n $scope.removeConditionalProduct = function (sku) {\\n // Find and remove item from an array\\n var i = $scope.conditionalProducts.indexOf(sku);\\n\\n if (i !== -1) {\\n $scope.conditionalProducts.splice(i, 1);\\n }\\n };\\n\\n $scope.updateServiceProductOrderline = function (data, placementDate, pickupDate, quantity, cartItem) {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'UpdateServiceProductInCart',\\n orderLineId: cartItem.Id,\\n quantity: quantity,\\n ServiceProperties: {\\n PlacementDate: placementDate,\\n PickupDate: pickupDate,\\n Timeslot: cartItem.Timeslot\\n },\\n sku: cartItem.Sku\\n }).success(function (data) {\\n _.each(data.Order.OrderLines, checkPlacementDate);\\n\\n $scope.cartOverview = data.Order;\\n $sessionStorage.NumberOfProducts = data.NumberOfProducts;\\n }).error(function (data) {\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup\\n });\\n };\\n\\n $scope.updateQuantity = function (quantity, orderLineId) {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'UpdateQuantity',\\n orderLineId: orderLineId,\\n quantity: quantity\\n }).success(function (data) {\\n $scope.cartOverview = data.Order; // Update datalayer\\n\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n return true;\\n }).error(function () {\\n return false;\\n });\\n };\\n\\n $scope.deleteFromCart = function (orderLineId) {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'RemoveOrderLineFromCart',\\n orderLineId: orderLineId\\n }).success(function (data) {\\n $scope.cartOverview = data.Order;\\n $sessionStorage.NumberOfProducts = data.NumberOfProducts;\\n $scope.productsInCartOverview = data.Order.OrderLines.length; // Update datalayer\\n\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n }).error(function (data) {\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup\\n });\\n };\\n\\n $scope.updateContractTerm = function () {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'UpdateContractTerm',\\n code: $scope.cartOverview.Contract.Code\\n }).success(function (data) {\\n $scope.cartOverview = data.Order;\\n $scope.cartOverview.Contract.IsValidContractDurationOption = true; // Update datalayer\\n\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n }).error(function (data) {\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup\\n });\\n };\\n\\n $scope.validateContractStartDate = function () {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'IsValidContractStartDate',\\n startDate: $scope.cartOverview.Contract.StartDate\\n }).success(function (data) {\\n $scope.cartOverview.Contract.IsValidStartDate = data;\\n }).error(function (data) {\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup\\n });\\n };\\n\\n $scope.initProductDetailPage = function () {\\n $scope.conditionalProducts = [];\\n };\\n\\n $scope.initCartOverview = function () {\\n $scope.cartOverview = [];\\n $scope.getCartOverview($scope.currentPage);\\n };\\n\\n $scope.setOrderQuestion = function (question, value) {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'SetOrderQuestionAnswer',\\n orderProperty: question,\\n value: value\\n }).success(function (data) {//TODO: error handling\\n });\\n };\\n\\n $scope.getCalendarRules = function (id, sku) {\\n var placementDateElement = $('.js-zebra-placementdate-' + id);\\n var pickupDateElement = $('.js-zebra-pickupdate-' + id);\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'GetCalendarRules',\\n sku: sku\\n }).success(function (data) {\\n placementDateElement.data('Zebra_DatePicker').update({\\n direction: [true, data.PlacementDateMaximumUpToDaysFromNow]\\n });\\n\\n if (pickupDateElement.length) {\\n pickupDateElement.data('Zebra_DatePicker').update({\\n direction: [data.PickupDateMinimumDaysFromPlacementDate, data.PickupDateMaximumDaysFromPlacementDate - 1]\\n });\\n }\\n });\\n };\\n\\n $scope.hasContractOptions = function () {\\n return $scope.productsInCartOverview && $scope.cartOverview.OrderLines?.filter(line => line.SubscriptionType === 2).length && !$scope.cartOverview.OrderLines?.filter(line => line.Product.PriceOnRequest).length;\\n };\\n\\n $scope.submitForm = function (event) {\\n let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;\\n const typeOfRequest = event.currentTarget.form.elements[\\\"typeOfRequest\\\"]; // is a duration selection made\\n\\n const IsValidContractDurationOption = $scope.cartOverview.Contract.Code !== null;\\n $scope.cartOverview.Contract.IsValidContractDurationOption = IsValidContractDurationOption; // update hidden field with correct order type\\n\\n if (typeOfRequest) {\\n typeOfRequest.value = type;\\n }\\n\\n $scope.submitting = true;\\n const contract = $scope.cartOverview.Contract;\\n\\n if (!$scope.hasContractOptions() || contract.IsValidStartDate && contract.IsValidContractDurationOption) {\\n event.currentTarget.form.submit();\\n }\\n };\\n}]);\"","module.exports = \"angular.module('catalog').controller('CatalogController', ['$scope', '$element', '$location', '$timeout', '$sessionStorage', '$document', '$window', '$cookies', 'GlobalService', function ($scope, $element, $location, $timeout, $sessionStorage, $document, $window, $cookies, GlobalService) {\\n var catalog = this;\\n var useFilterDependencies = false;\\n var showPricesWithVat = false;\\n $scope.triggerDataLayer = true;\\n $scope.dataLayerEvent = {\\n 'event': 'filter',\\n 'eventName': 'filter',\\n 'eventCategory': 'enhanced ecommerce',\\n 'eventAction': 'impressions',\\n 'eventLabel': 'filter'\\n };\\n\\n catalog.filter = function (queryOnUrl) {\\n queryOnUrl = typeof queryOnUrl !== 'undefined' ? queryOnUrl : true;\\n\\n if (useFilterDependencies == 'True') {\\n filterSequence();\\n } else {\\n filterFreeSelection();\\n }\\n /**\\r\\n * This function causes the selectbox filters to be dependend and function in a sequence.\\r\\n * second and thirth are disabled when first is not selected\\r\\n */\\n\\n\\n function filterSequence() {\\n //If the wastestream is selected, the filters should reset\\n if ($scope.selectedFilter1 != $scope.filter1) {\\n $scope.filter2 = null;\\n $scope.selectedFilter2 = '';\\n $scope.filter3 = null;\\n $scope.selectedFilter3 = '';\\n }\\n\\n if ($scope.selectedFilter2 != $scope.filter2) {\\n $scope.filter3 = null;\\n $scope.selectedFilter3 = '';\\n }\\n\\n if ($scope.filter1 && $scope.filter1 != '') {\\n $scope.selectedFilter1 = $scope.filter1;\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[0], $scope.filter1);\\n }\\n } else {\\n $scope.selectedFilter1 = '';\\n $scope.filter2 = '';\\n $scope.filter3 = '';\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[0], null);\\n }\\n }\\n\\n if ($scope.filter2) {\\n $scope.selectedFilter2 = $scope.filter2;\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[1], $scope.filter2);\\n }\\n } else {\\n $scope.selectedFilter2 = '';\\n $scope.filter3 = '';\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[1], null);\\n }\\n }\\n\\n if ($scope.filter3) {\\n $scope.selectedFilter3 = $scope.filter3;\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[2], $scope.filter3);\\n }\\n } else {\\n $scope.selectedFilter3 = '';\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[2], null);\\n }\\n }\\n } // end: filtersequence()\\n\\n /**\\r\\n * This function causes the selectbox filters to be free to choose\\r\\n * first, second and thirth are all enabled to choose from in the prefered order of the visitor\\r\\n */\\n\\n\\n function filterFreeSelection() {\\n $scope.selectedFilter1 = $scope.filter1;\\n $scope.selectedFilter2 = $scope.filter2;\\n $scope.selectedFilter3 = $scope.filter3;\\n\\n if (queryOnUrl) {\\n $location.search($scope.Filters[0], $scope.filter1);\\n $location.search($scope.Filters[1], $scope.filter2);\\n $location.search($scope.Filters[2], $scope.filter3);\\n }\\n } // end: filterFreeSelection()\\n\\n /**\\r\\n * Generate submit url\\r\\n */\\n\\n\\n if (typeof shopUrl != 'undefined') {\\n $scope.submitUrl = shopUrl;\\n } else {\\n var pathArray = window.location.pathname.split('/');\\n $scope.submitUrl = location.protocol + '//' + location.host + \\\"/\\\" + pathArray[1] + \\\"/\\\" + pathArray[2] + \\\"/\\\";\\n }\\n\\n if ($scope.filter1 != '' && $scope.filter1 != null) {\\n $scope.submitUrl += '#?' + $scope.Filters[0] + '=' + encodeURIComponent($scope.filter1);\\n } else if (typeof shopUrl != 'undefined') {\\n $scope.submitUrl = shopUrl;\\n }\\n\\n if ($scope.filter2 && $scope.filter2 != '') {\\n $scope.submitUrl += '&' + $scope.Filters[1] + '=' + encodeURIComponent($scope.filter2);\\n }\\n\\n if ($scope.filter3 && $scope.filter3 != '') {\\n $scope.submitUrl += '&' + $scope.Filters[2] + '=' + encodeURIComponent($scope.filter3);\\n }\\n\\n if ($scope.postbackOnChange) {\\n window.location = $scope.submitUrl;\\n } else {\\n catalog.getProductOverview(1);\\n }\\n }; // end: catalog.filter function\\n\\n\\n catalog.getProductOverview = function (page) {\\n let triggerDataLayer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\\n\\n if (page == 1) {\\n $scope.loading = true;\\n } else {\\n $location.search('page', page);\\n }\\n\\n $scope.buttonLoader = true;\\n $scope.currentPage = page;\\n var data = {\\n scController: 'Catalog',\\n scAction: 'GetCatalogOverview',\\n filter: {\\n CurrentPage: page,\\n RecordsPerPage: $scope.recordsPerPage,\\n IsBusiness: isBusinessUser(),\\n Filter: {\\n Filter1: $scope.selectedFilter1,\\n Filter2: $scope.selectedFilter2,\\n Filter3: $scope.selectedFilter3\\n },\\n IsPostBack: $scope.isPostBack,\\n Sorting: {\\n SortOrder: $scope.sortorder,\\n BranchId: $scope.BranchId,\\n SubBranchId: $scope.SubBranchId\\n }\\n }\\n };\\n GlobalService.getData(data).success(function (data) {\\n if ($scope.catalogOverview == undefined || $scope.catalogOverview.Products == undefined || page === 1) {\\n $scope.catalogOverview = data;\\n } else {\\n var products = $scope.catalogOverview.Products;\\n $scope.catalogOverview = data;\\n\\n for (var i = 0; i < products.length; i++) {\\n var productToAdd = products[products.length - i - 1];\\n productToAdd.isNew = false;\\n $scope.catalogOverview.Products.unshift(productToAdd);\\n }\\n }\\n\\n $scope.filter1 = data.DisplayProperties?.Filter?.Filter1;\\n $scope.filter2 = data.DisplayProperties?.Filter?.Filter2;\\n $scope.selectedFilter2 = data.DisplayProperties?.Filter?.Filter2;\\n $scope.filter3 = data.DisplayProperties?.Filter?.Filter3;\\n $scope.loading = false;\\n $scope.buttonLoader = false;\\n $scope.isPostBack = true;\\n $scope.postbackOnChange = data.DisplayProperties?.PostbackOnChange;\\n\\n if ($sessionStorage.productOverviewScroll != null && $sessionStorage.productOverviewScroll !== 0) {\\n window.scrollTo(0, $sessionStorage.productOverviewScroll);\\n $sessionStorage.productOverviewScroll = 0;\\n } // Handle Datalayer\\n\\n\\n if ($scope.triggerDataLayer && triggerDataLayer) {\\n // calculate from which index we'll return products\\n const startFrom = ($scope.currentPage - 1) * $scope.recordsPerPage;\\n const event = { ...$scope.dataLayerEvent,\\n filter_stream_type: $scope.filter1 || '',\\n filter_container_type: $scope.filter2 || '',\\n filter_capacity_type: $scope.filter3 || ''\\n };\\n $scope.handleDataLayer(data.Products, $scope.googleAnalyticsListName, startFrom, event);\\n }\\n }).error(function (e) {\\n console.info(e);\\n $timeout(function () {\\n $scope.loading = false;\\n }, 500);\\n });\\n };\\n\\n $scope.showContainersButtonClick = function () {\\n if ($scope.catalogOverview?.Products) {\\n dataLayer.push({ ...$scope.dataLayerEvent,\\n filter_stream_type: $scope.filter1 || '',\\n filter_container_type: $scope.filter2 || '',\\n filter_capacity_type: $scope.filter3 || ''\\n }); // Multiple products found\\n\\n if ($scope.catalogOverview.Products.length > 1) {\\n // Redirect to catalog page\\n window.location = $scope.submitUrl;\\n } // Only 1 product is found\\n else {\\n // Redirect to single product page\\n window.location = $scope.catalogOverview.Products[0].Url;\\n }\\n }\\n\\n return false;\\n };\\n\\n $scope.$on('BRANCH_UPDATE', function (event, data) {\\n $scope.BranchId = data.BranchId;\\n $scope.SubBranchId = data.SubBranchId;\\n catalog.getProductOverview(1, false);\\n });\\n\\n catalog.setTargetAudience = function (isBusiness, reload) {\\n reload = typeof reload !== 'undefined' ? reload : true; //Set the cookie for business, expires in 365 days\\n\\n $location.$search = {};\\n setCookie(\\\"isBusiness\\\", isBusiness, 365);\\n\\n if (reload) {\\n window.location = window.location.pathname;\\n }\\n\\n $scope.hideMessage = true;\\n };\\n\\n catalog.getQuerystringFilters = function () {\\n //Are there query string parameters to use for the filtering?\\n if ($location.search()[$scope.Filters[0]]) {\\n $scope.selectedFilter1 = $location.search()[$scope.Filters[0]];\\n $scope.filter1 = $scope.selectedFilter1;\\n }\\n\\n if ($location.search()[$scope.Filters[1]]) {\\n $scope.selectedFilter2 = $location.search()[$scope.Filters[1]];\\n $scope.filter2 = $scope.selectedFilter2;\\n }\\n\\n if ($location.search()[$scope.Filters[2]]) {\\n $scope.selectedFilter3 = $location.search()[$scope.Filters[2]];\\n $scope.filter3 = $scope.selectedFilter3;\\n }\\n\\n if ($location.search().page) {\\n $scope.recordsPerPage = $location.search().page * $scope.recordsPerPage;\\n }\\n };\\n\\n catalog.showAudienceMessage = function () {\\n var visitedCookie = getCookie(\\\"previousVisitor\\\");\\n\\n if (visitedCookie === 'true') {\\n $scope.previousVisitor = true;\\n } else {\\n $scope.previousVisitor = false;\\n setCookie(\\\"previousVisitor\\\", true, 365);\\n }\\n };\\n\\n catalog.showPricesWithVat = function () {\\n return showPricesWithVat;\\n };\\n\\n catalog.setScrollPosition = function () {\\n if ($(window).scrollTop() !== 0) {\\n sessionStorage.setItem('ngStorage-productOverviewScroll', $(window).scrollTop());\\n }\\n };\\n\\n catalog.resetFilters = function () {\\n $scope.selectedFilter1 = '';\\n $scope.selectedFilter2 = '';\\n $scope.selectedFilter3 = '';\\n };\\n\\n $('.c-shop-filter-form').on('click', '.js-reset-filters', function () {\\n catalog.resetFilters();\\n catalog.getProductOverview(1);\\n });\\n\\n $scope.initCatalogFilterComponent = function (data) {\\n if (typeof shopUrl !== 'undefined') {\\n $scope.submitUrl = shopUrl; // prefill default link target to shop\\n }\\n\\n $scope.triggerDataLayer = data.triggerDataLayer;\\n useFilterDependencies = data.UseFilterDependencies;\\n catalog.resetFilters();\\n $scope.Filters = data.Filters;\\n catalog.getProductOverview(1);\\n };\\n\\n $scope.initCatalogOverview = function (data) {\\n var BranchesCookieObj = $cookies.getObject('SelectedBranches');\\n $scope.BranchId = BranchesCookieObj ? BranchesCookieObj.BranchId : null;\\n $scope.SubBranchId = BranchesCookieObj ? BranchesCookieObj.SubBranchId : null; // Set var(s) global within controller\\n\\n useFilterDependencies = data.UseFilterDependencies !== undefined ? useFilterDependencies = data.UseFilterDependencies : 'False';\\n showPricesWithVat = data.ShowPricesWithVat == 'True' ? true : false;\\n\\n if ($location.search().business) {\\n if ($location.search().business == 'true') {\\n catalog.setTargetAudience(true, false);\\n } else {\\n catalog.setTargetAudience(false, false);\\n }\\n }\\n\\n catalog.resetFilters();\\n $scope.loading = false;\\n $scope.catalogOverview = [];\\n $scope.currentPage = 1;\\n $scope.recordsPerPage = 9;\\n $scope.tmpRecordsPerPage = $scope.recordsPerPage;\\n $scope.IsBusiness = isBusinessUser();\\n $scope.isPostBack = false;\\n $scope.Filters = data.Filters !== undefined ? data.Filters : ['', '', ''];\\n $scope.buttonLoader = false;\\n catalog.getQuerystringFilters();\\n catalog.showAudienceMessage();\\n catalog.getProductOverview($scope.currentPage, false);\\n\\n if ($scope.recordsPerPage !== $scope.tmpRecordsPerPage) {\\n $scope.recordsPerPage = $scope.tmpRecordsPerPage;\\n $scope.currentPage = parseInt($location.search().page);\\n }\\n };\\n}]);\"","module.exports = \"angular.module('checkoutFlow').controller('CheckoutFlowController', ['$rootScope', '$scope', '$sessionStorage', 'GlobalService', function ($rootScope, $scope, $sessionStorage, GlobalService) {\\n var checkoutFlow = this; // Get companies by name\\n\\n checkoutFlow.GetCompaniesByName = function () {\\n if ($scope.disableAutoCompleteOnCompanyName) {\\n $scope.disableAutoCompleteOnCompanyName = false;\\n return;\\n }\\n\\n if (typeof $scope.companyName == \\\"undefined\\\" || $scope.companyName.length < 2) {\\n $scope.companyList = [];\\n return;\\n }\\n\\n $scope.isLoading = true; // display loading icon\\n\\n $.post(window.location, {\\n scController: 'CheckoutFlow',\\n scAction: 'GetCompaniesByName',\\n companyName: $scope.companyName\\n }).done(function (data) {\\n $scope.companyList = data.Companies;\\n $scope.isLoading = false; // hide loading icon\\n\\n $scope.$apply();\\n }).error(function () {\\n $scope.companyList = [];\\n $scope.isLoading = false;\\n $scope.$apply();\\n });\\n }; // Get companies by coc number\\n\\n\\n checkoutFlow.GetCompaniesByCocNumber = function () {\\n if ($scope.disableAutoCompleteOnCocNumber) {\\n $scope.disableAutoCompleteOnCocNumber = false;\\n return;\\n }\\n\\n if (typeof $scope.cocNumber == \\\"undefined\\\" || $scope.cocNumber.length < 8) {\\n $scope.companyList = [];\\n return;\\n }\\n\\n $.post(window.location, {\\n scController: 'CheckoutFlow',\\n scAction: 'GetCompaniesByCocNumber',\\n cocNumber: $scope.cocNumber\\n }).done(function (data) {\\n $scope.companyList = data.Companies;\\n $scope.$apply();\\n });\\n }; // Get cart overview\\n\\n\\n checkoutFlow.GetCartOverview = function () {\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'GetShoppingCartOverview'\\n }).success(function (data) {\\n if (data !== undefined && data.Order.OrderLines !== undefined) {\\n $scope.cartOverview = data.Order;\\n }\\n });\\n }; // Set the selected company\\n\\n\\n checkoutFlow.SetCompany = function (company) {\\n $scope.disableAutoCompleteOnCompanyName = true;\\n $scope.disableAutoCompleteOnCocNumber = true;\\n $scope.company = company;\\n $scope.companyName = company.CompanyName;\\n $scope.cocNumber = company.CocNumber;\\n $scope.companyList = [];\\n validatePrefilledFields();\\n }; // Set the company name for prefill\\n\\n\\n checkoutFlow.SetCompanyName = function (companyName) {\\n $scope.disableAutoCompleteOnCompanyName = true;\\n $scope.companyName = companyName;\\n $scope.companyList = [];\\n }; // Set coc number for prefill\\n\\n\\n checkoutFlow.SetCocNumber = function (cocNumber) {\\n $scope.disableAutoCompleteOnCocNumber = true;\\n $scope.cocNumber = cocNumber;\\n $scope.companyList = [];\\n }; // Set coupon code\\n\\n\\n checkoutFlow.AddCouponCode = function (coupon) {\\n //TODO: Add zipcode to coupon validation on ucommerce\\n //var zipCode;\\n //if ($scope.deliveryAddress.Specified === 'True') {\\n // zipCode = $scope.deliveryAddress.ZipCode;\\n //} else {\\n // zipCode = $scope.company.ZipCode;\\n //}\\n GlobalService.postData({\\n scController: 'Cart',\\n scAction: 'AddCoupon',\\n coupon: coupon\\n }).success(function (data) {\\n $scope.showCouponAdded = true;\\n $scope.cartOverview = data.Order;\\n $sessionStorage.NumberOfProducts = data.NumberOfProducts;\\n $rootScope.$broadcast('CART_UPDATE', '');\\n }).error(function (data) {\\n var responseJSON = data ? data.error : 'error';\\n lightcase.start({\\n href: '#',\\n height: 'auto',\\n onFinish: {\\n getContent: function () {\\n var msg = $('

' + responseJSON + '

');\\n $('#lightcase-case .lightcase-inlineWrap').html(msg);\\n $(window).trigger('resize');\\n },\\n closeButton: function () {\\n $('.js-close-popup').on('click', function (e) {\\n e.preventDefault();\\n lightcase.close();\\n });\\n }\\n }\\n });\\n });\\n }; // Validate prefilled fields after selecting a company from autocomplete\\n\\n\\n function validatePrefilledFields() {\\n var $fieldBlurCheck = $('.js-field-blur-check');\\n setTimeout(function () {\\n $fieldBlurCheck.find('input').each(function () {\\n $(this).blur();\\n });\\n }, 200);\\n }\\n\\n checkoutFlow.blurCompany = function () {\\n setTimeout(function () {\\n $scope.companyList = [];\\n $scope.isLoading = false;\\n $scope.$apply();\\n }, 200);\\n };\\n\\n checkoutFlow.selectShipmentMethod = function (id) {\\n // If id equals null, get id from dom\\n if (id == undefined) {\\n id = $scope.selectedShipmentMethod;\\n } // Get shipping method field (hidden input)\\n\\n\\n var $shippingMethod = $('.js-shipping-method'); // Set value\\n\\n $shippingMethod.val(id);\\n }; // INIT function\\n\\n\\n $scope.init = function () {\\n $scope.test = $scope.company;\\n $scope.isLoading = false; // hide loading icon\\n\\n $scope.disableAutoCompleteOnCompanyName = false;\\n $scope.disableAutoCompleteOnCocNumber = false;\\n $scope.showCouponAdded = false;\\n $scope.canAddCouponCode = false;\\n $scope.deliveryAddress = {};\\n $scope.companyList = [];\\n $scope.cartOverview = []; // Get cart overview\\n\\n checkoutFlow.GetCartOverview();\\n }; // Watch changes on the company and coc input fields and call service for autocomplete\\n\\n\\n $scope.$watch(\\\"companyName\\\", checkoutFlow.GetCompaniesByName);\\n $scope.$watch(\\\"cocNumber\\\", checkoutFlow.GetCompaniesByCocNumber);\\n}]);\"","module.exports = \"angular.module('crossSell').controller('CrossSellController', ['$rootScope', '$scope', '$element', '$timeout', 'GlobalService', function ($rootScope, $scope, $element, $timeout, GlobalService) {\\n var nrOfProductsToShow = 3;\\n $scope.crossSellList = [];\\n $scope.dataLayerEvent = {\\n 'event': 'crosssell',\\n 'eventCategory': 'enhanced ecommerce',\\n 'eventAction': 'impressions',\\n 'eventLabel': 'crosssell'\\n };\\n $scope.$on('BRANCH_UPDATE', function (event, data) {\\n getCrossSellProducts(data.BranchId, data.SubBranchId);\\n });\\n\\n $scope.initCrossSell = function (products, googleAnalyticsListName) {\\n $scope.loading = false;\\n $scope.crossSellList = products; // Handle Datalayer\\n\\n $scope.googleAnalyticsListName = googleAnalyticsListName;\\n $scope.handleDataLayer($scope.crossSellList, $scope.googleAnalyticsListName, false, $scope.dataLayerEvent);\\n };\\n\\n function getCrossSellProducts(branchId, subBranchId) {\\n $scope.loading = true;\\n var data = {\\n scController: 'Catalog',\\n scAction: 'GetCatalogOverview',\\n filter: {\\n Sorting: {\\n BranchId: branchId,\\n SubBranchId: subBranchId\\n }\\n }\\n };\\n GlobalService.getData(data).success(function (data) {\\n $scope.loading = false;\\n $scope.crossSellList = data.Products.slice(0, nrOfProductsToShow); // Handle Datalayer\\n\\n $scope.handleDataLayer($scope.crossSellList, $scope.googleAnalyticsListName, false, $scope.dataLayerEvent);\\n }).error(function (e) {\\n $timeout(function () {\\n $scope.loading = false;\\n }, 500);\\n });\\n }\\n}]);\"","module.exports = \"angular.module('languageSwitch').controller('LanguageSwitchController', ['$rootScope', '$scope', '$sessionStorage', '$cookies', function ($rootScope, $scope, $sessionStorage, $cookies) {\\n $scope.selectedLanguage = '';\\n\\n $scope.switchLanguage = function ($event, newActiveLanguageBaseUrl) {\\n if ($event) {\\n $event.preventDefault();\\n }\\n\\n $cookies.remove('zipCode');\\n $cookies.remove('isBusiness');\\n window.location.href = newActiveLanguageBaseUrl;\\n /* $.post(window.location,\\r\\n {\\r\\n scController: 'Cart',\\r\\n scAction: 'ClearCart'\\r\\n }).done(function(data) {\\r\\n $scope.NrOfProducts = data.NumberOfProducts;\\r\\n $sessionStorage.NumberOfProducts = data.NumberOfProducts;\\r\\n $scope.$apply();\\r\\n window.location.href = newActiveLanguageBaseUrl;\\r\\n }).error(function(data) {\\r\\n alert(data.responseJSON.error);\\r\\n }); */\\n };\\n}]);\"","module.exports = \"angular.module('miniCart').controller('MiniCartController', ['$rootScope', '$scope', '$sessionStorage', function ($rootScope, $scope, $sessionStorage) {\\n $scope.$on('MINICART_UPDATE', function (event, arg) {\\n $scope.LoadMiniCart();\\n });\\n\\n $scope.LoadMiniCart = function () {\\n $scope.loading = true;\\n $.post(window.location, {\\n scController: 'Cart',\\n scAction: 'GetMiniShoppingCart'\\n }).done(function (data) {\\n $scope.cartItems = new Array(); // Slice array to chunks of two (because they are showed in two columns)\\n\\n var i,\\n counter = 0,\\n j,\\n tempArray,\\n chunk = 2;\\n\\n for (i = 0, j = data.RecentOrderLines.length; i < j; i += chunk) {\\n tempArray = data.RecentOrderLines.slice(i, i + chunk);\\n $scope.cartItems[counter] = tempArray;\\n counter++;\\n }\\n\\n $scope.NrOfProducts = data.NrOfProducts;\\n $sessionStorage.NumberOfProducts = data.NrOfProducts;\\n $scope.loading = false;\\n $scope.$apply();\\n });\\n };\\n\\n $scope.deleteFromCart = function (orderLineId) {\\n $.post(window.location, {\\n scController: 'Cart',\\n scAction: 'RemoveOrderLineFromCart',\\n orderLineId: orderLineId\\n }).done(function (data) {\\n $scope.LoadMiniCart(); // Update datalayer\\n\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n }).error(function (data) {\\n alert(data.responseJSON.error); // TODO: Nice popup\\n });\\n };\\n\\n $scope.initMiniCartOverview = function () {\\n $scope.NrOfProducts = 0;\\n $scope.LoadMiniCart();\\n };\\n}]);\"","module.exports = \"angular.module('productBundleForm').controller('ProductBundleFormController', ['$rootScope', '$scope', '$sessionStorage', 'GlobalService', function ($rootScope, $scope, $sessionStorage, GlobalService) {\\n $scope.isLoading = $scope.isSubmitted = false;\\n $scope.isSubmitted = false;\\n /**\\r\\n * Enable default button on form change\\r\\n * Normally after submit\\r\\n */\\n\\n $scope.addProductBundle = function (products) {\\n $scope.isLoading = true;\\n var options = {\\n scController: 'Cart',\\n scAction: 'AddBundledProductsToCart',\\n productForms: products\\n };\\n GlobalService.postData(options).success(function (data) {\\n $scope.isLoading = false;\\n $scope.isSubmitted = true;\\n\\n $scope.changeForm = function () {\\n $scope.isSubmitted = false;\\n };\\n\\n $rootScope.$broadcast('MINICART_UPDATE', '');\\n $rootScope.$broadcast('CART_UPDATE', '');\\n }).error(function (data) {\\n $scope.isLoading = false;\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup \\n });\\n };\\n}]);\"","module.exports = \"angular.module('productForm').controller('ProductFormController', ['$rootScope', '$scope', '$sessionStorage', '$filter', 'GlobalService', function ($rootScope, $scope, $sessionStorage, $filter, GlobalService) {\\n /**\\r\\n * isLoading - loading icon\\r\\n * isSucceeded - form post succeeded\\r\\n * isLocked - lock form to prevent posting data twice\\r\\n */\\n $scope.isLoading = $scope.isSucceeded = $scope.isLocked = false;\\n $scope.conditionalProducts = [];\\n /**\\r\\n * After submitting the product check whether the product submit is allowed:\\r\\n * If the cart is empty; allow adding the product\\r\\n * If the cart contains business items and the product is a business item; allow adding the product\\r\\n * If the cart contains consumer items and the product is a consumer item; allow adding the product\\r\\n *\\r\\n * or disallowed:\\r\\n * Cart has items of # category, product is from another category, give user option using modal:\\r\\n * Empty cart and add the desired product\\r\\n * Leave cart and don't add the desired product\\r\\n */\\n\\n $scope.addProductOrderline = function (event, fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot, productAllowed) {\\n if (!$scope.isLocked) {\\n $scope.isLocked = true;\\n var isValid = $('form#addProduct').valid();\\n const isQuickview = !!$(event.target).closest('.c-quickview').length;\\n\\n if (isValid) {\\n if (!productAllowed) {\\n lightcase.start({\\n href: '#',\\n // Needed to open modal programmaticially\\n onFinish: {\\n injectContent: function () {\\n // Element that holds modal content\\n var contentElement = $('#productNotAllowedInBasket'); // Set content\\n\\n var contentInner = lightcase.get('contentInner');\\n contentInner.children().html(contentElement.html()); // Resize lightcase to content\\n\\n lightcase.resize(); // Find DOM element that lightcase injects\\n\\n var lightcaseDom = lightcase.get('case'); // Setup default handler for DOM buttons click event which prevents default behaviour,\\n // closes the modal and optionally invoke a callback afterwards.\\n\\n var defaultModalClickHandler = (e, callback) => {\\n e.preventDefault();\\n lightcase.close();\\n\\n if (callback !== undefined) {\\n callback();\\n } // Remove lock when one of the buttons is clicked\\n\\n\\n $scope.isLocked = false;\\n }; // Bind click events on accept and reject buttons\\n\\n\\n lightcaseDom.find(\\\".js-accept\\\").on('click', e => defaultModalClickHandler(e, () => {\\n // The user gave permission to switch from one audience to another, this means the backend will empty the current cart\\n // and we can continue the flow of adding a item of the current audience\\n addProductOrderline(fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot, isQuickview);\\n }));\\n lightcaseDom.find(\\\".js-reject\\\").on('click', e => defaultModalClickHandler(e)); // Hide default close button for tablets resolutions and onwards\\n\\n $('.lightcase-icon-close').addClass(\\\"u-hidden@tablet-and-up\\\");\\n }\\n },\\n // Remove lock when user closes modal\\n onClose: {\\n resetLock: function () {\\n $scope.isLocked = false;\\n }\\n }\\n });\\n return false;\\n } // Cart contains no items yet or contains items that have the similear audience as the product to be added\\n\\n\\n addProductOrderline(fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot, isQuickview);\\n }\\n }\\n };\\n\\n $scope.onVariantChange = function (variant) {\\n $scope.changeForm();\\n\\n if (variant == null || $scope.price == null || $scope.price == 0) {\\n if ($scope.showPricesInclVat) {\\n $scope.price = $scope.variants[$scope.variants.length - 1].PriceIncVat;\\n } else {\\n $scope.price = $scope.variants[$scope.variants.length - 1].PriceExVat;\\n }\\n }\\n\\n if ($scope.showPricesInclVat) {\\n if (variant.PriceIncVat == 0) return;\\n $scope.price = variant.PriceIncVat;\\n } else {\\n if (variant.PriceExVat == 0) return;\\n $scope.price = variant.PriceExVat;\\n }\\n\\n $scope.updateVariants();\\n };\\n\\n $scope.updateVariants = function () {\\n if ($scope.variants == null || $scope.priceOnRequest || $scope.price == null || $scope.price == 0) return;\\n $scope.variants.forEach(function (variant) {\\n var priceDifference = ($scope.showPricesInclVat ? variant.PriceIncVat : variant.PriceExVat) - $scope.price; // Remove the \\\"(� ##.##)\\\" from frequency\\n\\n variant.Frequency = variant.Frequency.replace(/\\\\s*\\\\(.*?\\\\)\\\\s*$/g, \\\"\\\");\\n\\n if (priceDifference != 0) {\\n // Add \\\"(� ##.##)\\\" on frequency, Math.abs is required to put a plus sign\\n variant.Frequency += ' (' + (priceDifference > 0 ? '+' : '-') + $filter('currency')(Math.abs(priceDifference)) + ')';\\n }\\n });\\n };\\n /**\\r\\n * Internal private function that validates the passed form properties and tries to add an item to the cart.\\r\\n */\\n\\n\\n function addProductOrderline(fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot, isQuickview) {\\n $scope.isLoading = true;\\n var productForm = prepareProductFormForSubmit(fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot);\\n var options = {\\n scController: 'Cart',\\n scAction: 'AddProductToCart',\\n productForm: productForm\\n };\\n GlobalService.postData(options).success(function (data) {\\n $scope.isLoading = false;\\n $scope.isSucceeded = true;\\n $scope.addedQuantity = quantity;\\n $scope.LastCreatedOrderLineId = data.LastCreatedOrderLineId;\\n $sessionStorage.NumberOfProducts = data.NumberOfProducts; // Update datalayer\\n\\n data?.ECommerceDataLayerModels.forEach(data => {\\n if (data?.ecommerce?.add) {\\n data.ecommerce.add.actionField = {\\n list: isQuickview ? 'Quickview' : 'detail page'\\n };\\n }\\n });\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n $rootScope.$broadcast('MINICART_UPDATE', '');\\n $rootScope.$broadcast('CART_UPDATE', '');\\n }).error(function (data) {\\n $scope.isLoading = false;\\n $scope.isLocked = false;\\n alert(GlobalService.formatErrorMessage(data.error, data.validationData)); // TODO: Nice popup\\n });\\n }\\n /**\\r\\n * Prepares product for submit\\r\\n */\\n\\n\\n function prepareProductFormForSubmit(fullyQualifiedType, sku, quantity, variantSku, placementDate, pickupDate, timeSlot) {\\n var productForm = {\\n FullyQualifiedType: fullyQualifiedType,\\n ParentOrderlineId: $scope.$parent.LastCreatedOrderLineId,\\n SKU: sku,\\n Quantity: quantity,\\n VariantSku: variantSku,\\n AdditionalSkusToAdd: $scope.conditionalProducts,\\n PlacementDate: placementDate,\\n PickupDate: pickupDate,\\n Timeslot: timeSlot\\n };\\n return productForm;\\n }\\n /**\\r\\n * Enable default button on form change\\r\\n * Normally after submit\\r\\n */\\n\\n\\n $scope.changeForm = function () {\\n if (!$scope.isLoading) {\\n $scope.isLocked = false;\\n $scope.isSucceeded = false;\\n }\\n };\\n\\n $scope.$watch(\\\"quantity\\\", function (newValue, oldValue) {\\n if (newValue !== oldValue) {\\n $scope.isLocked = false;\\n $scope.isSucceeded = false;\\n }\\n });\\n /**\\r\\n * Add conditional product to conditionalProducts array\\r\\n */\\n\\n $scope.addConditionalProduct = function (sku) {\\n var i = $scope.conditionalProducts.indexOf(sku);\\n\\n if (i === -1) {\\n $scope.conditionalProducts.push(sku);\\n }\\n };\\n /**\\r\\n * Remove conditional product\\r\\n * Finds and removes item from array\\r\\n */\\n\\n\\n $scope.removeConditionalProduct = function (sku) {\\n var i = $scope.conditionalProducts.indexOf(sku);\\n\\n if (i !== -1) {\\n $scope.conditionalProducts.splice(i, 1);\\n }\\n };\\n}]);\"","module.exports = \"angular.module(\\\"search\\\").controller(\\\"SearchController\\\", [\\\"$scope\\\", \\\"$location\\\", function ($scope, $location) {\\n $scope.searchResults = [];\\n $scope.searchStr = \\\"\\\";\\n $scope.lastSearch = \\\"\\\";\\n $scope.noResults = false;\\n $scope.paging = {\\n index: 0,\\n total: 0,\\n pages: []\\n };\\n $scope.inputClass = '';\\n $scope.pageSize = 10;\\n\\n $scope.initSearchResults = function () {\\n const search = $location.search();\\n\\n if (search.query) {\\n $scope.searchStr = search.query;\\n $scope.paging.index = search.index || 0;\\n $scope.getSearchResults();\\n }\\n };\\n\\n $scope.keyUp = function (e) {\\n if ($scope.inputClass !== '') {\\n $scope.inputClass = '';\\n }\\n\\n if (e.key === \\\"Enter\\\" || e.keyCode === 13) {\\n this.doSearch();\\n }\\n };\\n\\n $scope.getSearchResults = function (paginate) {\\n if (!paginate) {\\n $scope.paging.index = 0;\\n $scope.lastSearch = $scope.searchStr;\\n }\\n\\n const data = {\\n Index: $scope.paging.index * $scope.pageSize,\\n Size: $scope.pageSize,\\n SearchQuery: paginate ? $scope.lastSearch : $scope.searchStr\\n };\\n fetch('/api/search', {\\n method: 'POST',\\n mode: 'cors',\\n cache: 'no-cache',\\n credentials: 'same-origin',\\n headers: {\\n 'Content-Type': 'application/json'\\n },\\n redirect: 'follow',\\n referrerPolicy: 'no-referrer',\\n body: JSON.stringify(data)\\n }).then(res => res.json()).then(res => {\\n $scope.searchResults = res.searchResults.map(result => {\\n result.class = `c-search__result__icon--${result.tag.toLowerCase()}`;\\n return result;\\n });\\n $scope.paging.total = res.totalItems;\\n $scope.paging.totalPages = Math.ceil(res.totalItems / $scope.pageSize);\\n $scope.noResults = $scope.paging.total === 0;\\n $scope.createPaging();\\n $scope.$apply();\\n }).catch(err => {\\n console.log(err);\\n });\\n };\\n\\n $scope.searchQuickLink = function (searchTerm) {\\n $scope.searchStr = searchTerm;\\n $scope.doSearch();\\n };\\n\\n $scope.createPaging = function () {\\n const n = $scope.paging.totalPages;\\n\\n if (n <= 1) {\\n $scope.paging.pages = [];\\n } else {\\n const pages = new Array(n).fill().map((_, i) => {\\n return {\\n pageNumber: i + 1,\\n class: \\\"\\\",\\n index: i\\n };\\n }).map((page, index) => {\\n if (page.index === $scope.paging.index) {\\n page.class = \\\"c-search__paging__button--current\\\";\\n }\\n\\n if (index < $scope.paging.index - 2 || index > $scope.paging.index + 2) {\\n return undefined;\\n }\\n\\n return page;\\n }).filter(page => page);\\n console.log(pages);\\n $scope.paging.pages = pages;\\n }\\n };\\n\\n $scope.paginate = function (index) {\\n $scope.paging.index = index;\\n $scope.getSearchResults(true);\\n };\\n\\n $scope.doSearch = function () {\\n $scope.setUrl();\\n\\n if ($scope.searchStr.length > 0) {\\n $scope.getSearchResults();\\n } else {\\n $scope.inputClass = \\\"error\\\";\\n }\\n };\\n\\n $scope.setUrl = function () {\\n console.log($scope.searchStr);\\n $location.search(\\\"query\\\", $scope.searchStr);\\n };\\n}]);\\n\\nconst setIcon = tag => {\\n const iconRoot = '~/Frontend/Renewi/dist/svg/renewi.sprite.svg#';\\n\\n switch (tag) {\\n default:\\n return [{\\n backgroundColor: \\\"#78be20\\\"\\n }, `${iconRoot}report`];\\n }\\n};\"","module.exports = \"angular.module('upsell').controller('UpsellController', ['$rootScope', '$scope', '$timeout', 'GlobalService', function ($rootScope, $scope, $timeout, GlobalService) {\\n $scope.dataLayerEvent = {\\n 'event': 'upsell',\\n 'eventCategory': 'enhanced ecommerce',\\n 'eventAction': 'impressions',\\n 'eventLabel': 'upsell'\\n };\\n $scope.$on('BRANCH_UPDATE', function (event, data) {\\n if ($scope.sku) {\\n getUpsellPackage($scope.sku, data.BranchId, data.SubBranchId);\\n }\\n });\\n\\n $scope.initUpsell = function (data, googleAnalyticsListName) {\\n $scope.loading = false;\\n $scope.buttonLoader = false;\\n $scope.addedToCart = false;\\n $scope.sku = data.ProductSku;\\n $scope.errors = {};\\n $scope.upsellList = extendUpsellItems(data.ProductForms);\\n updateCustomUpsellList();\\n $rootScope.$emit('BANNER_UPDATE', data); // Handle Datalayer\\n\\n var products = $scope.upsellList.map(function (element) {\\n return element.Product;\\n });\\n $scope.googleAnalyticsListName = $scope.googleAnalyticsListName || googleAnalyticsListName;\\n $scope.handleDataLayer(products, $scope.googleAnalyticsListName, false, $scope.dataLayerEvent);\\n };\\n\\n $scope.toggleUpsellInclude = function (Item, boolean) {\\n if (typeof boolean == 'undefined') {\\n Item.Include = !Item.Include;\\n } else {\\n Item.Include = boolean;\\n }\\n\\n Item.editableForm.$visible = false;\\n updateCustomUpsellList();\\n };\\n\\n $scope.updateUpsellItemOptions = function ($data, frequency, placementDate, Item) {\\n Item.PlacementDate = placementDate;\\n Item.EmptyingFrequency = frequency;\\n Item.editableForm.$visible = false;\\n };\\n\\n $scope.submitUpsellRequest = function () {\\n var productForms = [];\\n\\n _.each($scope.CustomUpsellList, function (element, index) {\\n productForms.push({\\n FullyQualifiedType: element.FullyQualifiedType,\\n Sku: element.Product.SKU,\\n VariantSku: element.Product.Variants != null ? element.EmptyingFrequency.SKU : null,\\n Quantity: 1,\\n PlacementDate: element.PlacementDate,\\n Product: {\\n Type: element.Product.Type\\n }\\n });\\n });\\n\\n var data = {\\n scController: 'Cart',\\n scAction: 'AddProductsToCart',\\n productForms: productForms\\n };\\n $scope.buttonLoader = true;\\n $scope.addedToCart = false;\\n GlobalService.postData(data).success(function (data) {\\n $scope.addedQuantity = productForms.length;\\n $scope.addedToCart = true;\\n $scope.buttonLoader = false;\\n $scope.updateMiniCart(); // Handle Datalayer\\n\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n }).error(function (data) {\\n appendErrorsToProductsAndOpenEditMode(data.validationData);\\n $scope.errors = data;\\n $scope.buttonLoader = false;\\n $scope.addedToCart = false;\\n console.error(data);\\n });\\n };\\n\\n $scope.isAddToCartButtonDisabled = function () {\\n return _.any($scope.upsellList, function (Item) {\\n if (Item.editableForm !== undefined) return Item.editableForm.$visible !== false ? true : false;\\n return false;\\n });\\n };\\n\\n $scope.updateMiniCart = function () {\\n $rootScope.$broadcast('MINICART_UPDATE', '');\\n };\\n\\n function appendErrorsToProductsAndOpenEditMode(errors) {\\n _.each($scope.upsellList, function (Item, index) {\\n var error = _.find(errors, function (validationData) {\\n return validationData[\\\"Sku\\\"] == Item.Product.SKU;\\n });\\n\\n if (error) {\\n Item.error = error;\\n Item.editableForm.$visible = true;\\n }\\n });\\n }\\n\\n function updateCustomUpsellList() {\\n var CustomUpsellList = _.filter($scope.upsellList, function (Item) {\\n return Item.Include !== false;\\n });\\n\\n $scope.CustomUpsellList = CustomUpsellList;\\n } // Extend UpsellDataArray\\n\\n\\n function extendUpsellItems(productForms) {\\n _.each(productForms, function (productForm, index) {\\n productForm.Include = true;\\n productForm.PlacementDate = moment(productForm.PlacementDate).format('DD-MM-YYYY');\\n\\n if (productForm.VariantSku) {\\n var EmptyingFrequency = _.filter(productForm.Product.Variants, function (Variant) {\\n return Variant.SKU === productForm.VariantSku;\\n });\\n\\n productForm.EmptyingFrequency = EmptyingFrequency[0];\\n } // If EmptyingFrequency is not set, pick first\\n else if (productForm.Product.Variants != null && productForm.EmptyingFrequency == undefined) {\\n productForm.EmptyingFrequency = productForm.Product.Variants[0];\\n }\\n });\\n\\n return productForms;\\n }\\n\\n function getUpsellPackage(sku, branchId, subBranchId) {\\n $scope.loading = true;\\n var data = {\\n scController: 'Upsell',\\n scAction: 'GetUpsellPackage',\\n Sku: sku,\\n BranchId: branchId,\\n SubbranchId: subBranchId\\n };\\n $scope.buttonLoader = true;\\n GlobalService.getData(data).success(function (data) {\\n // Empty current upsellList so forms get reinitialized\\n $scope.upsellList = [];\\n $scope.initUpsell(data);\\n $scope.buttonLoader = false;\\n }).error(function (data) {\\n console.error(data);\\n });\\n }\\n}]);\"","module.exports = \"angular.module('wizard').controller('WizardController', ['$scope', '$element', 'ChartService', 'GlobalService', function ($scope, $element, ChartService, GlobalService) {\\n var wizard = this,\\n wizUserData = JSON.parse(localStorage.getItem('wizUserData')) || {},\\n UnitVolume,\\n AmountOptions = {\\n Rol: {\\n Name: 'zakken',\\n IconUrl: '/Frontend/Renewi/dist/img/icons/garbagebag.svg',\\n Unit: {\\n Name: 'Liters',\\n Volume: 'Liter'\\n },\\n Type: 'Bags',\\n Frequency: 'week'\\n },\\n Afzet: {\\n Name: 'aanhangwagens',\\n IconUrl: '/Frontend/Renewi/dist/img/icons/trailer.svg',\\n Unit: {\\n Name: 'CubicMeters',\\n Volume: 'm³'\\n },\\n Type: 'Trailers',\\n Frequency: 'once'\\n }\\n };\\n $scope.steps = [{\\n id: '#step1',\\n active: true\\n }, {\\n id: '#step2',\\n active: false\\n }, {\\n id: '#step3',\\n active: false\\n }, {\\n id: '#step4',\\n active: false\\n }, {\\n id: '#step5',\\n active: false\\n }, {\\n id: '#stapContact',\\n actief: false\\n }, {\\n id: '#stapOffer',\\n actief: false\\n }];\\n $scope.Branches = {};\\n $scope.SelectedStreams = [];\\n $scope.buttonLoader = false;\\n $scope.dataLayerEvent = {\\n 'event': 'wizard',\\n 'eventCategory': 'enhanced ecommerce',\\n 'eventAction': 'impressions',\\n 'eventLabel': 'wizard'\\n };\\n /** -- Branches ----------------------------- **/\\n\\n $scope.initWizardBranches = function (data) {\\n // Add 'Branches' object if it doesnt exist\\n if (typeof wizUserData.Branches === 'undefined') {\\n wizUserData.Branches = {\\n Branche: null,\\n SubBranche: null\\n };\\n }\\n\\n $scope.Branches.Branche = data.Branches;\\n $scope.Branches.SubBranche = data.SubBranches;\\n $scope.Branches.SelectedBranche = wizUserData.Branches.Branche;\\n $scope.Branches.SelectedSubBranche = wizUserData.Branches.SubBranche;\\n $scope.$watchGroup(['Branches.SelectedBranche', 'Branches.SelectedSubBranche'], $scope.updateBranches);\\n };\\n\\n $scope.updateSelect = function () {};\\n\\n $scope.updateBranches = function () {\\n // Set wizUserData branches based on selected branche/sub-branche\\n wizUserData.Branches.Branche = $scope.Branches.SelectedBranche;\\n wizUserData.Branches.SubBranche = $scope.Branches.SelectedSubBranche;\\n $scope.updateUserData(); // Update wizUserData\\n\\n $scope.steps[1].active = false;\\n $scope.steps[2].active = false;\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false;\\n $scope.steps[6].active = false;\\n };\\n /** -- Branches ----------------------------- **/\\n\\n /** -- WasteStreams ----------------------------- **/\\n\\n\\n $scope.getWasteStreams = function () {\\n var data = {\\n scController: 'DecisionAid',\\n scAction: 'GetWasteStreams',\\n BranchId: $scope.Branches.SelectedBranche.Value,\\n SubbranchId: $scope.Branches.SelectedSubBranche.Value,\\n ItemId: $scope.guid\\n };\\n $scope.buttonLoader = true;\\n GlobalService.getData(data).success(function (data) {\\n $scope.steps[1].active = data.WasteStreams ? true : false;\\n $scope.steps[5].active = data.EnableDirectContact ? true : false;\\n\\n if (data.WasteStreams) {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/' + document.location.search)\\n });\\n } else {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/contact-voor-advies/' + document.location.search)\\n });\\n }\\n\\n $scope.wasteStreams = data.WasteStreams; // Extend wasteStreams\\n\\n _.each($scope.wasteStreams, function (Stream, index) {\\n _.extend(Stream, {\\n Amount: {\\n Frequency: AmountOptions[Stream.ContainerType].Frequency,\\n Liters: 0,\\n CubicMeters: 0,\\n Value: '',\\n Name: AmountOptions[Stream.ContainerType].Name,\\n Type: AmountOptions[Stream.ContainerType].Type,\\n IconUrl: AmountOptions[Stream.ContainerType].IconUrl,\\n Unit: {\\n Name: AmountOptions[Stream.ContainerType].Unit.Name,\\n Volume: AmountOptions[Stream.ContainerType].Unit.Volume\\n }\\n }\\n });\\n\\n Stream.Selected = Stream.PreSelect;\\n }); // Set selected streams based on pre-selected waste streams\\n\\n\\n $scope.SelectedStreams = _.filter(data.WasteStreams, function (stream) {\\n return stream.PreSelect !== false;\\n }); // Set waste streams savings chart\\n\\n if ($scope.SelectedStreams.length) getSavings();\\n if (data.WasteStreams) GlobalService.scrollTo($scope.steps[1].id);\\n if (data.EnableDirectContact) GlobalService.scrollTo($scope.steps[5].id);\\n $scope.buttonLoader = false;\\n }).error(function (e) {\\n console.info(e);\\n });\\n }; // change the state of the waste stream\\n\\n\\n $scope.selectWasteStream = function (stream) {\\n $scope.steps[2].active = false;\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false;\\n $scope.steps[6].active = false; //Toggle selected state\\n\\n stream.Selected = stream.Selected ? false : true; // Set selected streams based on pre-selected waste streams\\n\\n $scope.SelectedStreams = _.filter($scope.wasteStreams, function (stream) {\\n return stream.Selected !== false;\\n });\\n getSavings(); // Update stream chart\\n }; // Sync scope selected streams with previously selected (localStorage) choises\\n\\n\\n $scope.$watch('SelectedStreams', function (SelectedStreams) {\\n // Set wizUserData selected streams\\n wizUserData.SelectedStreams = $scope.SelectedStreams;\\n $scope.updateUserData(); // Update wizUserData\\n\\n if (!$scope.SelectedStreams.length) {\\n $scope.steps[2].active = false;\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n } else {\\n $scope.steps[5].active = false;\\n }\\n }, true); // create a default waste streams chart\\n\\n $scope.wasteStreamsChart = ChartService.create({\\n percent: 0,\\n step: 0,\\n options: {\\n gradientBeginColor: '#0161AE',\\n gradientEndColor: '#39BB5D',\\n textColor: '#0161AE',\\n size: 180,\\n lineWidth: 10\\n }\\n });\\n\\n function getSavings() {\\n var data = {\\n scController: 'DecisionAid',\\n scAction: 'GetSavings',\\n BranchId: $scope.Branches.SelectedBranche.Value,\\n SubbranchId: $scope.Branches.SelectedSubBranche.Value,\\n WasteStreams: _.pluck($scope.SelectedStreams, 'Value'),\\n ItemId: $scope.guid\\n };\\n GlobalService.getData(data).success(function (data) {\\n $scope.wasteStreamsChart.percent = data.RawMaterialSavings;\\n }).error(function (e) {\\n console.info(e);\\n });\\n }\\n\\n $scope.moreInfo = function (e, stream) {\\n e.preventDefault();\\n lightcase.start({\\n href: '#',\\n onFinish: {\\n baz: function () {\\n // dummycontent, change to description in stream info\\n var content = \\\"

\\\" + stream.Name + \\\"

\\\\\\r\\n

\\\" + stream.Description + \\\"

\\\";\\n $('.lightcase-inlineWrap').html(content);\\n lightcase.resize();\\n }\\n }\\n });\\n };\\n /** -- WasteStreams ----------------------------- **/\\n\\n /** -- Amount ----------------------------- **/\\n\\n\\n $scope.initAmountPanel = function () {\\n if ($scope.SelectedStreams.length) {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/hoeveelheid/' + document.location.search)\\n });\\n } else {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/contact-voor-advies/' + document.location.search)\\n });\\n }\\n\\n $scope.steps[2].active = $scope.SelectedStreams.length ? true : false;\\n $scope.steps[5].active = $scope.SelectedStreams.length ? false : true;\\n GlobalService.scrollTo($scope.SelectedStreams.length ? $scope.steps[2].id : $scope.steps[5].id);\\n };\\n\\n $scope.changeStreamAmountFrequency = function (stream, frequency) {\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false;\\n stream.Amount.Frequency = frequency;\\n };\\n\\n function round(value, precision) {\\n var multiplier = Math.pow(10, precision || 0);\\n return Math.round(value * multiplier) / multiplier;\\n }\\n\\n $scope.changeStreamAmount = function (stream) {\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false; // first we determine the weight per bag\\n\\n var liter = stream.Amount.Value * UnitVolume[stream.Amount.Type],\\n cubic = liter / 1000;\\n stream.Amount.Liters = round(liter);\\n stream.Amount.CubicMeters = round(cubic, 1);\\n };\\n /** -- Amount ----------------------------- **/\\n\\n /** -- ExtraChoices ----------------------------- **/\\n\\n\\n $scope.initExtraChoices = function () {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/wensen/' + document.location.search)\\n });\\n $scope.steps[3].active = true;\\n GlobalService.scrollTo($scope.steps[3].id);\\n }; // Sync scope extra choices with previously selected (localStorage) choices\\n\\n\\n $scope.ExtraChoices = wizUserData.ExtraChoices || {\\n ThroughDoor: false,\\n OnParkingSpot: false\\n };\\n $scope.$watch('ExtraChoices', function (ExtraChoices) {\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false;\\n $scope.steps[6].active = false;\\n wizUserData.ExtraChoices = ExtraChoices;\\n $scope.updateUserData();\\n }, true);\\n /** -- ExtraChoices ----------------------------- **/\\n\\n /** -- Advice ----------------------------- **/\\n\\n $scope.adviceList = [];\\n\\n $scope.initAdvicePanel = function () {\\n var WasteStreams = {};\\n\\n _.each($scope.SelectedStreams, function (element, index) {\\n var tmpObject = [];\\n tmpObject[element.Value] = {\\n Volume: element.Amount.Liters,\\n Interval: element.Amount.Frequency\\n };\\n\\n _.extend(WasteStreams, tmpObject);\\n });\\n\\n var data = {\\n scController: 'DecisionAid',\\n scAction: 'GetAdvice',\\n BranchId: $scope.Branches.SelectedBranche.Value,\\n SubbranchId: $scope.Branches.SelectedSubBranche.Value,\\n ItemId: $scope.guid,\\n WasteStreams: WasteStreams,\\n Specials: $scope.ExtraChoices\\n };\\n $scope.buttonLoader = true;\\n GlobalService.getData(data).success(function (data) {\\n if (data.EnableDirectContact) {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/contact-voor-advies/' + document.location.search)\\n });\\n $scope.steps[5].active = true;\\n GlobalService.scrollTo($scope.steps[5].id);\\n } else if (data.length) {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/advies/' + document.location.search)\\n });\\n $scope.steps[4].active = true;\\n $scope.steps[6].active = true;\\n $scope.adviceList = data; // Extend adviceList\\n\\n _.each($scope.adviceList, function (Advice, index) {\\n Advice.Include = true;\\n Advice.IsValidPickupDate = true;\\n\\n if (Advice.VariantSku) {\\n var Ledegingsfrequentie = _.filter(Advice.Product.Variants, function (Variant) {\\n return Variant.SKU == Advice.VariantSku;\\n });\\n\\n Advice.Ledegingsfrequentie = Ledegingsfrequentie[0];\\n }\\n });\\n\\n $scope.getWasteProfile(WasteStreams);\\n GlobalService.scrollTo($scope.steps[4].id);\\n }\\n\\n $scope.buttonLoader = false; // Handle Datalayer\\n\\n var products = data.map(function (product) {\\n return product.Product;\\n });\\n $scope.handleDataLayer(products, $scope.googleAnalyticsListName, false, $scope.dataLayerEvent);\\n }).error(function (e) {\\n console.info(e);\\n });\\n };\\n\\n $scope.getWasteProfile = function (WasteStreams) {\\n var data = {\\n scController: 'DecisionAid',\\n scAction: 'GetWasteProfile',\\n BranchId: $scope.Branches.SelectedBranche.Value,\\n SubbranchId: $scope.Branches.SelectedSubBranche.Value,\\n ItemId: $scope.guid,\\n WasteStreams: WasteStreams\\n };\\n GlobalService.getData(data).success(function (data) {\\n $scope.WasteProfile = data;\\n google.charts.load(\\\"current\\\", {\\n packages: [\\\"corechart\\\"]\\n });\\n google.charts.setOnLoadCallback(drawChart);\\n\\n function drawChart() {\\n var data = google.visualization.arrayToDataTable([['Task', 'Hours per Day'], ['Grondstof', $scope.WasteProfile.RawMaterials], ['Groene energie', $scope.WasteProfile.GreenEnergy], ['Grijze energie', $scope.WasteProfile.GreyEnergy], ['Resudu', $scope.WasteProfile.Residu]]);\\n var options = {\\n legend: 'none',\\n enableInteractivity: false,\\n pieHole: 0.88,\\n tooltip: {\\n trigger: 'none'\\n },\\n pieSliceText: 'none',\\n chartArea: {\\n left: 0,\\n top: 0,\\n width: '100%',\\n height: '100%'\\n },\\n slices: {\\n 0: {\\n color: '#0161AE'\\n },\\n 1: {\\n color: '#39BB5D'\\n },\\n 2: {\\n color: '#E0E2E4'\\n },\\n 3: {\\n color: '#1FBBEF'\\n }\\n }\\n };\\n var chart = new google.visualization.PieChart(document.getElementById('js-wizard-profile-chart'));\\n chart.draw(data, options);\\n }\\n }).error(function (e) {\\n console.info(e);\\n });\\n };\\n\\n $scope.toggleAdviceInclude = function (stream, boolean) {\\n stream.Include = boolean;\\n };\\n\\n $scope.$watch('adviceList', function () {\\n var CustomAdvice = _.filter($scope.adviceList, function (Advice) {\\n return Advice.Include !== false;\\n });\\n\\n $scope.CustomAdvice = CustomAdvice;\\n $scope.steps[5].active = $scope.CustomAdvice.length ? false : true;\\n $scope.steps[6].active = $scope.CustomAdvice.length ? true : false;\\n }, true);\\n\\n $scope.updateAdvice = function (data, placementDate, pickupDate, advice) {\\n var newPlacementDate = moment(placementDate, 'DD-MM-YYYY').format('YYYY-MM-DDTHH:mm:ssZ'),\\n newPickupDate = moment(pickupDate, 'DD-MM-YYYY').format('YYYY-MM-DDTHH:mm:ssZ');\\n\\n if (newPickupDate > newPlacementDate) {\\n advice.IsValidPickupDate = true;\\n if (pickupDate) advice.PickupDate = newPickupDate;\\n if (placementDate) advice.PlacementDate = newPlacementDate;\\n } else {\\n advice.IsValidPickupDate = false;\\n return 'Invalid Pickup Date';\\n }\\n };\\n /** -- Advice ----------------------------- **/\\n\\n /** -- OfferRequest ----------------------------- **/\\n\\n\\n $scope.submitOfferRequest = function (url) {\\n var Products = [];\\n\\n _.each($scope.CustomAdvice, function (element, index) {\\n Products[Products.length] = {\\n ProductSku: element.Product.SKU,\\n VariantSku: element.VariantSku,\\n Amount: element.Quantity,\\n PlacementDate: element.PlacementDate,\\n PickupDate: element.PickupDate\\n };\\n });\\n\\n var data = {\\n scController: 'DecisionAid',\\n scAction: 'GetQuote',\\n ItemId: $scope.guid,\\n Products: Products\\n };\\n $scope.buttonLoader = true;\\n GlobalService.getData(data).success(function (data) {\\n if (data.CartUpdated) {\\n window.location = url;\\n } else {\\n $scope.steps[5].active = true;\\n GlobalService.scrollTo($scope.steps[5].id);\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + '/' + GlobalService.toNiceName($scope.Branches.SelectedBranche.Name) + '/' + GlobalService.toNiceName($scope.Branches.SelectedSubBranche.Name) + '/contact-voor-advies/' + document.location.search)\\n });\\n }\\n\\n $scope.buttonLoader = false;\\n window.dataLayerHelpers.updateCart(data.ECommerceDataLayerModels);\\n }).error(function (e) {\\n console.info(e);\\n });\\n };\\n /** -- OfferRequest ----------------------------- **/\\n\\n /** -- Base ----------------------------- **/\\n\\n\\n $scope.updateUserData = function () {\\n if (window.localStorage) localStorage.setItem('wizUserData', JSON.stringify(wizUserData));\\n };\\n\\n $scope.init = function (guid, trashbagVolume, trailerVolume, translationBags, translationTrailers, googleAnalyticsListName) {\\n $scope.guid = guid;\\n UnitVolume = {\\n Bags: trashbagVolume ? parseFloat(trashbagVolume) : 40,\\n Trailers: trailerVolume ? parseFloat(trailerVolume) : 1600\\n };\\n $scope.googleAnalyticsListName = googleAnalyticsListName;\\n\\n if (window.location.hash === $scope.steps[1].id && wizUserData.Branches.SubBranche) {\\n $scope.Branches.SelectedBranche = wizUserData.Branches.Branche;\\n $scope.Branches.SelectedSubBranche = wizUserData.Branches.SubBranche;\\n $scope.getWasteStreams();\\n } else {\\n dataLayer.push({\\n 'event': 'virtualPageview',\\n 'virtualDocumentPath': GlobalService.toUrl(document.location.pathname + document.location.search)\\n });\\n }\\n };\\n\\n $scope.startWizard = function () {\\n $scope.getWasteStreams();\\n $scope.steps[1].active = false;\\n $scope.steps[2].active = false;\\n $scope.steps[3].active = false;\\n $scope.steps[4].active = false;\\n $scope.steps[5].active = false;\\n $scope.steps[6].active = false;\\n };\\n\\n $scope.startWizardChat = function ($event, msg) {\\n $event.preventDefault();\\n\\n if (typeof $zopim !== 'undefined') {\\n var chatNotes = '';\\n $zopim.livechat.say(msg);\\n chatNotes += 'Branche: ' + $scope.Branches.SelectedBranche.Name + '\\\\n';\\n chatNotes += 'Sub-branche: ' + $scope.Branches.SelectedSubBranche.Name + '\\\\n';\\n chatNotes += '\\\\n';\\n if (!_.isEmpty($scope.SelectedStreams)) chatNotes += 'Selected stream: \\\\n';\\n\\n _.each($scope.SelectedStreams, function (Stream, index) {\\n chatNotes += Stream.Name + '\\\\n';\\n chatNotes += Stream.Amount[Stream.Amount.Unit.Name] + ' ' + Stream.Amount.Unit.Name + '\\\\n';\\n chatNotes += Stream.Amount.Frequency + '\\\\n\\\\n';\\n });\\n\\n if ($scope.ExtraChoices.ThroughDoor || $scope.ExtraChoices.OnParkingSpot) chatNotes += 'Extra choise: \\\\n';\\n if ($scope.ExtraChoices.ThroughDoor) chatNotes += document.getElementById('fit_through_door').dataset.zopimNote + '\\\\n';\\n if ($scope.ExtraChoices.OnParkingSpot) chatNotes += document.getElementById('parking_space').dataset.zopimNote + '\\\\n';\\n $zopim.livechat.setNotes(chatNotes);\\n }\\n };\\n /** -- Base ----------------------------- **/\\n\\n}]);\"","module.exports = \"angular.module(\\\"zipcode\\\").controller(\\\"zipcodeController\\\", [\\\"$rootScope\\\", \\\"$scope\\\", \\\"$sessionStorage\\\", \\\"$cookies\\\", function ($rootScope, $scope, $sessionStorage, $cookies) {\\n $scope.initZipcode = function (zipCode) {\\n $scope.zipCode = zipCode;\\n $scope.value = zipCode || $scope.postalPlaceholder;\\n };\\n\\n $scope.openPopup = function () {\\n const event = new CustomEvent('openZipCodePopup', {\\n detail: $scope.value !== $scope.placeholder ? $scope.value : null\\n });\\n window.dispatchEvent(event);\\n };\\n}]);\"","module.exports = \"angular.module('shopApp').directive('addToCartButton', function () {\\n return {\\n restrict: 'AE',\\n template: '',\\n scope: {\\n translation: '=',\\n // translate for default state\\n translationadded: '=',\\n // translate when submitted (green button)\\n isLoading: '=',\\n // true when loading (loader button)\\n isSubmitted: '=',\\n // true when submitted (green button)\\n addedQuantity: '='\\n },\\n link: function ($scope, element, attrs) {}\\n };\\n});\"","module.exports = \"// global language\\nvar translations = {\\n nl: {\\n month: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'],\\n day: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],\\n format: 'dd-mm-jjjj',\\n formatDatepicker: 'd-m-Y'\\n },\\n en: {\\n month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\\n day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\\n format: 'mm-dd-yyyy',\\n formatDatepicker: 'm-d-Y'\\n },\\n fr: {\\n month: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Julliet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],\\n day: ['Dimanche', 'Lundi', 'Mardi', 'Mecredi', 'Jeudi', 'Vendredi', 'Samedi'],\\n format: 'jj-mm-aaaa',\\n formatDatepicker: 'd-m-Y'\\n }\\n};\\n\\nvar setDatePicker = function (disabledDates, element, scope, ngModel) {\\n var currentLang = $('html').attr('lang') ? $('html').attr('lang') : 'en';\\n\\n if (disabledDates === null || disabledDates === undefined) {\\n disabledDates = [];\\n } //Add sunday to the disabled dates\\n\\n\\n disabledDates.push(\\\"* * * 0\\\");\\n var zebraOptions = {\\n first_day_of_week: 1,\\n direction: true,\\n show_select_today: false,\\n show_icon: false,\\n show_clear_date: false,\\n select_other_months: true,\\n disabled_dates: disabledDates,\\n container: element.closest('.c-input-date'),\\n format: translations[currentLang].formatDatepicker,\\n months: translations[currentLang].month,\\n days: translations[currentLang].day,\\n onOpen: function () {\\n $(this).prop('disabled', true);\\n },\\n onClose: function () {\\n $(this).prop('disabled', false);\\n },\\n onSelect: function (dateText) {\\n scope.$apply(function () {\\n ngModel.$setViewValue(dateText);\\n }); // Trigger on change event\\n\\n $(this).change();\\n }\\n }; //// Dynamic placementDate - Sitecore setting\\n\\n if ($(element).attr('ng-model') === 'placementDate') {\\n // Pair pickupDate with placementDate\\n zebraOptions.pair = $('input[ng-model=pickupDate]');\\n zebraOptions.direction = [true, $(element).attr('maxdaysfromnow')];\\n\\n if ($(element).attr('maxdaysfromnow') === '0') {\\n zebraOptions.direction = 1;\\n }\\n } // Dynamic pickupDate relative to placementDate - Sitecore setting\\n\\n\\n if ($(element).attr('ng-model') === 'pickupDate') {\\n zebraOptions.direction = [$(element).attr('mindaysfromplacementdate'), $(element).attr('maxdaysfromplacementdate') - 1];\\n\\n if ($(element).attr('maxdaysfromplacementdate') === '0') {\\n zebraOptions.direction = 1;\\n }\\n }\\n\\n element.Zebra_DatePicker(zebraOptions);\\n};\\n\\nangular.module('shopApp').directive('datepicker', function () {\\n return {\\n require: 'ngModel',\\n link: function (scope, el, attr, ngModel) {\\n var sku = $('input[id=sku]').val() ? $('input[id=sku]').val() : scope.SKU;\\n $.post(window.location, {\\n scController: 'Cart',\\n scAction: 'GetNonDeliveryDates',\\n sku: sku\\n }).error(function () {\\n setDatePicker(null, $(el), scope, ngModel);\\n }).done(function (data) {\\n setDatePicker(data, $(el), scope, ngModel);\\n });\\n }\\n };\\n});\"","module.exports = \"/**\\r\\n * BEWARE This directive is a custom edited version of https://github.com/rendro/easy-pie-chart\\r\\n * So DON'T just update this directive without the proper checks\\r\\n */\\nangular.module('wizard').directive('easypiechart', function () {\\n return {\\n restrict: 'AE',\\n require: '?ngModel',\\n scope: {\\n percent: '=',\\n options: '='\\n },\\n link: function (scope, element, attrs) {\\n scope.percent = scope.percent || 0;\\n /**\\r\\n * default easy pie chart options\\r\\n * @type {Object}\\r\\n */\\n\\n var options = {\\n barColor: '#ef1e25',\\n trackColor: '#f9f9f9',\\n scaleColor: '#dfe0e0',\\n scaleLength: 5,\\n lineCap: 'round',\\n lineWidth: 3,\\n size: 110,\\n rotate: 0,\\n animate: {\\n duration: 1000,\\n enabled: true\\n }\\n };\\n scope.options = angular.extend(options, scope.options);\\n var pieChart = new EasyPieChart(element[0], options);\\n scope.$watch('percent', function (newVal, oldVal) {\\n pieChart.update(newVal);\\n });\\n }\\n };\\n});\\n/**\\r\\n * Renderer to render the chart on a canvas object\\r\\n * @param {DOMElement} el DOM element to host the canvas (root of the plugin)\\r\\n * @param {object} options options object of the plugin\\r\\n */\\n\\nvar CanvasRenderer = function (el, options) {\\n var cachedBackground;\\n var canvas = document.createElement('canvas');\\n el.appendChild(canvas);\\n\\n if (typeof G_vmlCanvasManager === 'object') {\\n G_vmlCanvasManager.initElement(canvas);\\n }\\n\\n var ctx = canvas.getContext('2d');\\n canvas.width = canvas.height = options.size; // canvas on retina devices\\n\\n var scaleBy = 1;\\n\\n if (window.devicePixelRatio > 1) {\\n scaleBy = window.devicePixelRatio;\\n canvas.style.width = canvas.style.height = [options.size, 'px'].join('');\\n canvas.width = canvas.height = options.size * scaleBy;\\n ctx.scale(scaleBy, scaleBy);\\n } // move 0,0 coordinates to the center\\n\\n\\n ctx.translate(options.size / 2, options.size / 2); // rotate canvas -90deg\\n\\n ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);\\n var radius = (options.size - options.lineWidth) / 2;\\n\\n if (options.scaleColor && options.scaleLength) {\\n radius -= options.scaleLength + 2; // 2 is the distance between scale and bar\\n } // IE polyfill for Date\\n\\n\\n Date.now = Date.now || function () {\\n return +new Date();\\n };\\n /**\\r\\n * Draw a circle around the center of the canvas\\r\\n * @param {strong} color Valid CSS color string\\r\\n * @param {number} lineWidth Width of the line in px\\r\\n * @param {number} percent Percentage to draw (float between -1 and 1)\\r\\n */\\n\\n\\n var drawCircle = function (color, lineWidth, percent) {\\n percent = Math.min(Math.max(-1, percent || 0), 1);\\n var isNegative = percent <= 0 ? true : false;\\n ctx.beginPath();\\n ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);\\n ctx.strokeStyle = color;\\n ctx.lineWidth = lineWidth;\\n ctx.stroke();\\n };\\n /**\\r\\n * Draw the scale of the chart\\r\\n */\\n\\n\\n var drawScale = function () {\\n var offset;\\n var length;\\n ctx.lineWidth = 1;\\n ctx.fillStyle = options.scaleColor;\\n ctx.save();\\n\\n for (var i = 24; i > 0; --i) {\\n if (i % 6 === 0) {\\n length = options.scaleLength;\\n offset = 0;\\n } else {\\n length = options.scaleLength * 0.6;\\n offset = options.scaleLength - length;\\n }\\n\\n ctx.fillRect(-options.size / 2 + offset, 0, length, 1);\\n ctx.rotate(Math.PI / 12);\\n }\\n\\n ctx.restore();\\n };\\n /**\\r\\n * Request animation frame wrapper with polyfill\\r\\n * @return {function} Request animation frame method or timeout fallback\\r\\n */\\n\\n\\n var reqAnimationFrame = function () {\\n return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {\\n window.setTimeout(callback, 1000 / 60);\\n };\\n }();\\n /**\\r\\n * Draw the background of the plugin including the scale and the track\\r\\n */\\n\\n\\n var drawBackground = function () {\\n if (options.scaleColor) drawScale();\\n if (options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);\\n };\\n /**\\r\\n * Canvas accessor\\r\\n */\\n\\n\\n this.getCanvas = function () {\\n return canvas;\\n };\\n /**\\r\\n * Canvas 2D context 'ctx' accessor\\r\\n */\\n\\n\\n this.getCtx = function () {\\n return ctx;\\n };\\n /**\\r\\n * Clear the complete canvas\\r\\n */\\n\\n\\n this.clear = function () {\\n ctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);\\n };\\n /**\\r\\n * Draw the complete chart\\r\\n * @param {number} percent Percent shown by the chart between -100 and 100\\r\\n */\\n\\n\\n this.draw = function (percent) {\\n // do we need to render a background\\n if (!!options.scaleColor || !!options.trackColor) {\\n // getImageData and putImageData are supported\\n if (ctx.getImageData && ctx.putImageData) {\\n if (!cachedBackground) {\\n drawBackground();\\n cachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);\\n } else {\\n ctx.putImageData(cachedBackground, 0, 0);\\n }\\n } else {\\n this.clear();\\n drawBackground();\\n }\\n } else {\\n this.clear();\\n }\\n\\n ctx.lineCap = options.lineCap; // if barcolor is a function execute it and pass the percent as a value\\n\\n var color;\\n\\n if (typeof options.barColor === 'function') {\\n color = options.barColor(percent);\\n } else {\\n color = options.barColor;\\n } // draw bar\\n\\n\\n drawCircle(color, options.lineWidth, percent / 100);\\n }.bind(this);\\n /**\\r\\n * Animate from some percent to some other percentage\\r\\n * @param {number} from Starting percentage\\r\\n * @param {number} to Final percentage\\r\\n */\\n\\n\\n this.animate = function (from, to) {\\n var startTime = Date.now();\\n options.onStart(from, to);\\n\\n var animation = function () {\\n var process = Math.min(Date.now() - startTime, options.animate.duration);\\n var currentValue = options.easing(this, process, from, to - from, options.animate.duration);\\n this.draw(currentValue);\\n options.onStep(from, to, currentValue);\\n\\n if (process >= options.animate.duration) {\\n options.onStop(from, to);\\n } else {\\n reqAnimationFrame(animation);\\n }\\n }.bind(this);\\n\\n reqAnimationFrame(animation);\\n }.bind(this);\\n};\\n\\nvar EasyPieChart = function (el, opts) {\\n var defaultOptions = {\\n barColor: '#ef1e25',\\n trackColor: '#f9f9f9',\\n scaleColor: '#dfe0e0',\\n scaleLength: 5,\\n lineCap: 'round',\\n lineWidth: 3,\\n trackWidth: undefined,\\n size: 110,\\n rotate: 0,\\n animate: {\\n duration: 1000,\\n enabled: true\\n },\\n easing: function (x, t, b, c, d) {\\n // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/\\n t = t / (d / 2);\\n\\n if (t < 1) {\\n return c / 2 * t * t + b;\\n }\\n\\n return -c / 2 * (--t * (t - 2) - 1) + b;\\n },\\n onStart: function (from, to) {\\n return;\\n },\\n onStep: function (from, to, currentValue) {\\n return;\\n },\\n onStop: function (from, to) {\\n return;\\n }\\n }; // detect present renderer\\n\\n if (typeof CanvasRenderer !== 'undefined') {\\n defaultOptions.renderer = CanvasRenderer;\\n } else if (typeof SVGRenderer !== 'undefined') {\\n defaultOptions.renderer = SVGRenderer;\\n } else {\\n throw new Error('Please load either the SVG- or the CanvasRenderer');\\n }\\n\\n var options = {};\\n var currentValue = 0;\\n /**\\r\\n * Initialize the plugin by creating the options object and initialize rendering\\r\\n */\\n\\n var init = function () {\\n this.el = el;\\n this.options = options; // merge user options into default options\\n\\n for (var i in defaultOptions) {\\n if (defaultOptions.hasOwnProperty(i)) {\\n options[i] = opts && typeof opts[i] !== 'undefined' ? opts[i] : defaultOptions[i];\\n\\n if (typeof options[i] === 'function') {\\n options[i] = options[i].bind(this);\\n }\\n }\\n } // check for jQuery easing\\n\\n\\n if (typeof options.easing === 'string' && typeof jQuery !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {\\n options.easing = jQuery.easing[options.easing];\\n } else {\\n options.easing = defaultOptions.easing;\\n } // process earlier animate option to avoid bc breaks\\n\\n\\n if (typeof options.animate === 'number') {\\n options.animate = {\\n duration: options.animate,\\n enabled: true\\n };\\n }\\n\\n if (typeof options.animate === 'boolean' && !options.animate) {\\n options.animate = {\\n duration: 1000,\\n enabled: options.animate\\n };\\n } // create renderer\\n\\n\\n this.renderer = new options.renderer(el, options); // initial draw\\n\\n this.renderer.draw(currentValue); // initial update\\n\\n if (el.dataset && el.dataset.percent) {\\n this.update(parseFloat(el.dataset.percent));\\n } else if (el.getAttribute && el.getAttribute('data-percent')) {\\n this.update(parseFloat(el.getAttribute('data-percent')));\\n }\\n }.bind(this);\\n /**\\r\\n * Update the value of the chart\\r\\n * @param {number} newValue Number between 0 and 100\\r\\n * @return {object} Instance of the plugin for method chaining\\r\\n */\\n\\n\\n this.update = function (newValue) {\\n newValue = parseFloat(newValue);\\n\\n if (options.animate.enabled) {\\n this.renderer.animate(currentValue, newValue);\\n } else {\\n this.renderer.draw(newValue);\\n }\\n\\n currentValue = newValue;\\n return this;\\n }.bind(this);\\n /**\\r\\n * Disable animation\\r\\n * @return {object} Instance of the plugin for method chaining\\r\\n */\\n\\n\\n this.disableAnimation = function () {\\n options.animate.enabled = false;\\n return this;\\n };\\n /**\\r\\n * Enable animation\\r\\n * @return {object} Instance of the plugin for method chaining\\r\\n */\\n\\n\\n this.enableAnimation = function () {\\n options.animate.enabled = true;\\n return this;\\n };\\n\\n init();\\n};\"","module.exports = \"angular.module('shopApp').directive('fallbackSrc', function () {\\n var fallbackSrc = {\\n link: function postLink(scope, iElement, iAttrs) {\\n iElement.bind('error', function () {\\n angular.element(this).attr(\\\"src\\\", iAttrs.fallbackSrc);\\n });\\n }\\n };\\n return fallbackSrc;\\n});\"","module.exports = \"angular.module('shopApp').directive('lightbox', function () {\\n return {\\n link: function (scope, el, attr, ngModel) {\\n el.lightcase({\\n functionBefore: function (origin, continueTooltip) {\\n origin.tooltipster('content', origin.children('.js-tooltip-content').html());\\n continueTooltip();\\n },\\n interactive: 'true',\\n animation: 'fade',\\n delay: 200,\\n theme: 'tooltipster-shadow',\\n contentAsHTML: true,\\n touchDevices: false,\\n trigger: 'hover'\\n });\\n }\\n };\\n});\"","module.exports = \"angular.module('shopApp').directive('quantityInput', function () {\\n return {\\n restrict: 'AE',\\n template: `\\n
\\n \\n Min 1\\n \\n \\n \\n Plus 1\\n \\n
\\n `,\\n scope: {\\n quantity: '='\\n },\\n link: function ($scope, element, attrs) {\\n $scope.quantity = $scope.quantity || 1;\\n\\n $scope.quantityUp = function () {\\n $scope.quantity++;\\n };\\n\\n $scope.quantityDown = function () {\\n if ($scope.quantity > 1) {\\n $scope.quantity--;\\n }\\n };\\n }\\n };\\n});\"","module.exports = \"angular.module('shopApp').directive('tooltip', function () {\\n return {\\n link: function (scope, el) {\\n var content = el.find('.js-tooltip-content');\\n\\n if (content.length === 0) {\\n content.parent('.c-tooltip').hide();\\n return;\\n }\\n\\n el.tooltipster({\\n functionBefore: function (origin, continueTooltip) {\\n origin.tooltipster('content', origin.children('.js-tooltip-content').html());\\n continueTooltip();\\n },\\n interactive: 'true',\\n animation: 'fade',\\n delay: 200,\\n theme: 'tooltipster-shadow',\\n contentAsHTML: true,\\n touchDevices: true,\\n trigger: 'hover'\\n });\\n }\\n };\\n});\"","module.exports = \"/*\\r\\nblauw: #0161AE\\r\\ngroen: #39BB5D\\r\\ngrijs: #E0E2E4\\r\\n */\\nangular.module('wizard').service('ChartService', function () {\\n function drawMultiRadiantCircle(ctx, xc, yc, r, lineWidth, radientColors) {\\n var partLength = 2 * Math.PI / radientColors.length;\\n var start = 0;\\n var gradient = null;\\n var startColor = null,\\n endColor = null;\\n\\n for (var i = 0; i < radientColors.length; i++) {\\n startColor = radientColors[i];\\n endColor = radientColors[(i + 1) % radientColors.length];\\n var xStart = xc + Math.cos(start) * r;\\n var xEnd = xc + Math.cos(start + partLength) * r;\\n var yStart = yc + Math.sin(start) * r;\\n var yEnd = yc + Math.sin(start + partLength) * r;\\n ctx.beginPath();\\n gradient = ctx.createLinearGradient(xStart, yStart, xEnd, yEnd);\\n gradient.addColorStop(0, startColor);\\n gradient.addColorStop(1.0, endColor);\\n ctx.strokeStyle = gradient;\\n ctx.arc(xc, yc, r, start, start + partLength);\\n ctx.lineWidth = lineWidth;\\n ctx.stroke();\\n ctx.closePath();\\n start += partLength;\\n }\\n\\n return gradient;\\n }\\n /**\\r\\n * Default options for easypiechart rendering\\r\\n * @type {Object}\\r\\n */\\n\\n\\n var defaultOptions = {\\n animate: {\\n duration: 1000,\\n enabled: true\\n },\\n trackColor: '#E0E2E4',\\n // background color\\n textColor: '#0161AE',\\n // text color\\n barColor: function (percent) {\\n var canvas = this.renderer.getCanvas();\\n var tmpCanvas = document.createElement('canvas');\\n var tmpCtx = tmpCanvas.getContext('2d');\\n return drawMultiRadiantCircle(tmpCtx, 0, 0, canvas.width / 4, this.options.lineWidth, [this.options.gradientBeginColor || '#0161AE', this.options.gradientEndColor || '#39BB5D']);\\n },\\n scaleColor: false,\\n lineWidth: 20,\\n lineCap: 'circle',\\n size: 120,\\n // in pixels\\n onStep: function (from, to, stepValue) {\\n this.el.children[0].innerHTML = '' + Math.ceil(stepValue) + '%';\\n }\\n };\\n /**\\r\\n * Create a new chart instance\\r\\n * @param {Object} options configuration options\\r\\n * @return {Object} new Chart object\\r\\n */\\n\\n function create(config) {\\n return {\\n percent: config.percent,\\n options: angular.extend(defaultOptions, config.options)\\n };\\n }\\n /**\\r\\n * Expose methods\\r\\n */\\n\\n\\n return {\\n create: create\\n };\\n});\"","module.exports = \"angular.module('shopApp').service('GlobalService', function ($http) {\\n /**\\r\\n * Global service call for getting data from API\\r\\n * @param {Object} data object which contains configuration data\\r\\n * @return {Deferred} Deferred with the ajax call\\r\\n */\\n function getData(data) {\\n // Should be http.get\\n return $http.post(window.location.href, data);\\n }\\n /**\\r\\n * Global service call for posting data to API\\r\\n * @param {Object} data object which contains configuration data\\r\\n * @return {Deferred} Deferred with the ajax call\\r\\n */\\n\\n\\n function postData(data) {\\n return $http.post(window.location.href, data);\\n }\\n /**\\r\\n * Scroll to element\\r\\n * @param {Object} elementID Id of the element to scroll to\\r\\n * @return {Object} new Chart object\\r\\n */\\n\\n\\n function scrollTo(elementID) {\\n setTimeout(function () {\\n $('html, body').delay(100).stop().animate({\\n scrollTop: $(elementID).offset().top\\n }, 1000);\\n }, 100);\\n }\\n /**\\r\\n * Convert string to nice name\\r\\n * @param {Object} string The string to be converted\\r\\n * @return {Object} new nice name string \\r\\n */\\n\\n\\n function toNiceName(string) {\\n return string.replace(/[^a-z0-9]+/ig, \\\"-\\\").toLowerCase();\\n }\\n /**\\r\\n * Convert string to url\\r\\n * @param {Object} options The string to be converted\\r\\n * @return {Object} new url string\\r\\n */\\n\\n\\n function toUrl(string) {\\n return string.replace(/([^:])(\\\\/\\\\/+)/g, '$1/').replace(/\\\\/$/, \\\"\\\");\\n }\\n\\n function formatErrorMessage(error, validationData) {\\n var errorMessage = error;\\n\\n if (validationData) {\\n errorMessage = '';\\n angular.forEach(validationData, function (item) {\\n errorMessage += item.Message + '\\\\n';\\n });\\n }\\n\\n return errorMessage;\\n }\\n /**\\r\\n * Expose methods\\r\\n */\\n\\n\\n return {\\n getData: getData,\\n postData: postData,\\n scrollTo: scrollTo,\\n toNiceName: toNiceName,\\n toUrl: toUrl,\\n formatErrorMessage: formatErrorMessage\\n };\\n});\"","module.exports = \"/**\\r\\n * @license AngularJS v1.5.0\\r\\n * (c) 2010-2016 Google, Inc. http://angularjs.org\\r\\n * License: MIT\\r\\n */\\n(function (window, angular, undefined) {\\n 'use strict';\\n /* jshint ignore:start */\\n\\n var noop = angular.noop;\\n var copy = angular.copy;\\n var extend = angular.extend;\\n var jqLite = angular.element;\\n var forEach = angular.forEach;\\n var isArray = angular.isArray;\\n var isString = angular.isString;\\n var isObject = angular.isObject;\\n var isUndefined = angular.isUndefined;\\n var isDefined = angular.isDefined;\\n var isFunction = angular.isFunction;\\n var isElement = angular.isElement;\\n var ELEMENT_NODE = 1;\\n var COMMENT_NODE = 8;\\n var ADD_CLASS_SUFFIX = '-add';\\n var REMOVE_CLASS_SUFFIX = '-remove';\\n var EVENT_CLASS_PREFIX = 'ng-';\\n var ACTIVE_CLASS_SUFFIX = '-active';\\n var PREPARE_CLASS_SUFFIX = '-prepare';\\n var NG_ANIMATE_CLASSNAME = 'ng-animate';\\n var NG_ANIMATE_CHILDREN_DATA = '$$ngAnimateChildren'; // Detect proper transitionend/animationend event names.\\n\\n var CSS_PREFIX = '',\\n TRANSITION_PROP,\\n TRANSITIONEND_EVENT,\\n ANIMATION_PROP,\\n ANIMATIONEND_EVENT; // If unprefixed events are not supported but webkit-prefixed are, use the latter.\\n // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.\\n // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`\\n // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.\\n // Register both events in case `window.onanimationend` is not supported because of that,\\n // do the same for `transitionend` as Safari is likely to exhibit similar behavior.\\n // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit\\n // therefore there is no reason to test anymore for other vendor prefixes:\\n // http://caniuse.com/#search=transition\\n\\n if (isUndefined(window.ontransitionend) && isDefined(window.onwebkittransitionend)) {\\n CSS_PREFIX = '-webkit-';\\n TRANSITION_PROP = 'WebkitTransition';\\n TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';\\n } else {\\n TRANSITION_PROP = 'transition';\\n TRANSITIONEND_EVENT = 'transitionend';\\n }\\n\\n if (isUndefined(window.onanimationend) && isDefined(window.onwebkitanimationend)) {\\n CSS_PREFIX = '-webkit-';\\n ANIMATION_PROP = 'WebkitAnimation';\\n ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';\\n } else {\\n ANIMATION_PROP = 'animation';\\n ANIMATIONEND_EVENT = 'animationend';\\n }\\n\\n var DURATION_KEY = 'Duration';\\n var PROPERTY_KEY = 'Property';\\n var DELAY_KEY = 'Delay';\\n var TIMING_KEY = 'TimingFunction';\\n var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';\\n var ANIMATION_PLAYSTATE_KEY = 'PlayState';\\n var SAFE_FAST_FORWARD_DURATION_VALUE = 9999;\\n var ANIMATION_DELAY_PROP = ANIMATION_PROP + DELAY_KEY;\\n var ANIMATION_DURATION_PROP = ANIMATION_PROP + DURATION_KEY;\\n var TRANSITION_DELAY_PROP = TRANSITION_PROP + DELAY_KEY;\\n var TRANSITION_DURATION_PROP = TRANSITION_PROP + DURATION_KEY;\\n\\n var isPromiseLike = function (p) {\\n return p && p.then ? true : false;\\n };\\n\\n var ngMinErr = angular.$$minErr('ng');\\n\\n function assertArg(arg, name, reason) {\\n if (!arg) {\\n throw ngMinErr('areq', \\\"Argument '{0}' is {1}\\\", name || '?', reason || \\\"required\\\");\\n }\\n\\n return arg;\\n }\\n\\n function mergeClasses(a, b) {\\n if (!a && !b) return '';\\n if (!a) return b;\\n if (!b) return a;\\n if (isArray(a)) a = a.join(' ');\\n if (isArray(b)) b = b.join(' ');\\n return a + ' ' + b;\\n }\\n\\n function packageStyles(options) {\\n var styles = {};\\n\\n if (options && (options.to || options.from)) {\\n styles.to = options.to;\\n styles.from = options.from;\\n }\\n\\n return styles;\\n }\\n\\n function pendClasses(classes, fix, isPrefix) {\\n var className = '';\\n classes = isArray(classes) ? classes : classes && isString(classes) && classes.length ? classes.split(/\\\\s+/) : [];\\n forEach(classes, function (klass, i) {\\n if (klass && klass.length > 0) {\\n className += i > 0 ? ' ' : '';\\n className += isPrefix ? fix + klass : klass + fix;\\n }\\n });\\n return className;\\n }\\n\\n function removeFromArray(arr, val) {\\n var index = arr.indexOf(val);\\n\\n if (val >= 0) {\\n arr.splice(index, 1);\\n }\\n }\\n\\n function stripCommentsFromElement(element) {\\n if (element instanceof jqLite) {\\n switch (element.length) {\\n case 0:\\n return [];\\n break;\\n\\n case 1:\\n // there is no point of stripping anything if the element\\n // is the only element within the jqLite wrapper.\\n // (it's important that we retain the element instance.)\\n if (element[0].nodeType === ELEMENT_NODE) {\\n return element;\\n }\\n\\n break;\\n\\n default:\\n return jqLite(extractElementNode(element));\\n break;\\n }\\n }\\n\\n if (element.nodeType === ELEMENT_NODE) {\\n return jqLite(element);\\n }\\n }\\n\\n function extractElementNode(element) {\\n if (!element[0]) return element;\\n\\n for (var i = 0; i < element.length; i++) {\\n var elm = element[i];\\n\\n if (elm.nodeType == ELEMENT_NODE) {\\n return elm;\\n }\\n }\\n }\\n\\n function $$addClass($$jqLite, element, className) {\\n forEach(element, function (elm) {\\n $$jqLite.addClass(elm, className);\\n });\\n }\\n\\n function $$removeClass($$jqLite, element, className) {\\n forEach(element, function (elm) {\\n $$jqLite.removeClass(elm, className);\\n });\\n }\\n\\n function applyAnimationClassesFactory($$jqLite) {\\n return function (element, options) {\\n if (options.addClass) {\\n $$addClass($$jqLite, element, options.addClass);\\n options.addClass = null;\\n }\\n\\n if (options.removeClass) {\\n $$removeClass($$jqLite, element, options.removeClass);\\n options.removeClass = null;\\n }\\n };\\n }\\n\\n function prepareAnimationOptions(options) {\\n options = options || {};\\n\\n if (!options.$$prepared) {\\n var domOperation = options.domOperation || noop;\\n\\n options.domOperation = function () {\\n options.$$domOperationFired = true;\\n domOperation();\\n domOperation = noop;\\n };\\n\\n options.$$prepared = true;\\n }\\n\\n return options;\\n }\\n\\n function applyAnimationStyles(element, options) {\\n applyAnimationFromStyles(element, options);\\n applyAnimationToStyles(element, options);\\n }\\n\\n function applyAnimationFromStyles(element, options) {\\n if (options.from) {\\n element.css(options.from);\\n options.from = null;\\n }\\n }\\n\\n function applyAnimationToStyles(element, options) {\\n if (options.to) {\\n element.css(options.to);\\n options.to = null;\\n }\\n }\\n\\n function mergeAnimationDetails(element, oldAnimation, newAnimation) {\\n var target = oldAnimation.options || {};\\n var newOptions = newAnimation.options || {};\\n var toAdd = (target.addClass || '') + ' ' + (newOptions.addClass || '');\\n var toRemove = (target.removeClass || '') + ' ' + (newOptions.removeClass || '');\\n var classes = resolveElementClasses(element.attr('class'), toAdd, toRemove);\\n\\n if (newOptions.preparationClasses) {\\n target.preparationClasses = concatWithSpace(newOptions.preparationClasses, target.preparationClasses);\\n delete newOptions.preparationClasses;\\n } // noop is basically when there is no callback; otherwise something has been set\\n\\n\\n var realDomOperation = target.domOperation !== noop ? target.domOperation : null;\\n extend(target, newOptions); // TODO(matsko or sreeramu): proper fix is to maintain all animation callback in array and call at last,but now only leave has the callback so no issue with this.\\n\\n if (realDomOperation) {\\n target.domOperation = realDomOperation;\\n }\\n\\n if (classes.addClass) {\\n target.addClass = classes.addClass;\\n } else {\\n target.addClass = null;\\n }\\n\\n if (classes.removeClass) {\\n target.removeClass = classes.removeClass;\\n } else {\\n target.removeClass = null;\\n }\\n\\n oldAnimation.addClass = target.addClass;\\n oldAnimation.removeClass = target.removeClass;\\n return target;\\n }\\n\\n function resolveElementClasses(existing, toAdd, toRemove) {\\n var ADD_CLASS = 1;\\n var REMOVE_CLASS = -1;\\n var flags = {};\\n existing = splitClassesToLookup(existing);\\n toAdd = splitClassesToLookup(toAdd);\\n forEach(toAdd, function (value, key) {\\n flags[key] = ADD_CLASS;\\n });\\n toRemove = splitClassesToLookup(toRemove);\\n forEach(toRemove, function (value, key) {\\n flags[key] = flags[key] === ADD_CLASS ? null : REMOVE_CLASS;\\n });\\n var classes = {\\n addClass: '',\\n removeClass: ''\\n };\\n forEach(flags, function (val, klass) {\\n var prop, allow;\\n\\n if (val === ADD_CLASS) {\\n prop = 'addClass';\\n allow = !existing[klass];\\n } else if (val === REMOVE_CLASS) {\\n prop = 'removeClass';\\n allow = existing[klass];\\n }\\n\\n if (allow) {\\n if (classes[prop].length) {\\n classes[prop] += ' ';\\n }\\n\\n classes[prop] += klass;\\n }\\n });\\n\\n function splitClassesToLookup(classes) {\\n if (isString(classes)) {\\n classes = classes.split(' ');\\n }\\n\\n var obj = {};\\n forEach(classes, function (klass) {\\n // sometimes the split leaves empty string values\\n // incase extra spaces were applied to the options\\n if (klass.length) {\\n obj[klass] = true;\\n }\\n });\\n return obj;\\n }\\n\\n return classes;\\n }\\n\\n function getDomNode(element) {\\n return element instanceof angular.element ? element[0] : element;\\n }\\n\\n function applyGeneratedPreparationClasses(element, event, options) {\\n var classes = '';\\n\\n if (event) {\\n classes = pendClasses(event, EVENT_CLASS_PREFIX, true);\\n }\\n\\n if (options.addClass) {\\n classes = concatWithSpace(classes, pendClasses(options.addClass, ADD_CLASS_SUFFIX));\\n }\\n\\n if (options.removeClass) {\\n classes = concatWithSpace(classes, pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX));\\n }\\n\\n if (classes.length) {\\n options.preparationClasses = classes;\\n element.addClass(classes);\\n }\\n }\\n\\n function clearGeneratedClasses(element, options) {\\n if (options.preparationClasses) {\\n element.removeClass(options.preparationClasses);\\n options.preparationClasses = null;\\n }\\n\\n if (options.activeClasses) {\\n element.removeClass(options.activeClasses);\\n options.activeClasses = null;\\n }\\n }\\n\\n function blockTransitions(node, duration) {\\n // we use a negative delay value since it performs blocking\\n // yet it doesn't kill any existing transitions running on the\\n // same element which makes this safe for class-based animations\\n var value = duration ? '-' + duration + 's' : '';\\n applyInlineStyle(node, [TRANSITION_DELAY_PROP, value]);\\n return [TRANSITION_DELAY_PROP, value];\\n }\\n\\n function blockKeyframeAnimations(node, applyBlock) {\\n var value = applyBlock ? 'paused' : '';\\n var key = ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY;\\n applyInlineStyle(node, [key, value]);\\n return [key, value];\\n }\\n\\n function applyInlineStyle(node, styleTuple) {\\n var prop = styleTuple[0];\\n var value = styleTuple[1];\\n node.style[prop] = value;\\n }\\n\\n function concatWithSpace(a, b) {\\n if (!a) return b;\\n if (!b) return a;\\n return a + ' ' + b;\\n }\\n\\n var $$rAFSchedulerFactory = ['$$rAF', function ($$rAF) {\\n var queue, cancelFn;\\n\\n function scheduler(tasks) {\\n // we make a copy since RAFScheduler mutates the state\\n // of the passed in array variable and this would be difficult\\n // to track down on the outside code\\n queue = queue.concat(tasks);\\n nextTick();\\n }\\n\\n queue = scheduler.queue = [];\\n /* waitUntilQuiet does two things:\\r\\n * 1. It will run the FINAL `fn` value only when an uncanceled RAF has passed through\\r\\n * 2. It will delay the next wave of tasks from running until the quiet `fn` has run.\\r\\n *\\r\\n * The motivation here is that animation code can request more time from the scheduler\\r\\n * before the next wave runs. This allows for certain DOM properties such as classes to\\r\\n * be resolved in time for the next animation to run.\\r\\n */\\n\\n scheduler.waitUntilQuiet = function (fn) {\\n if (cancelFn) cancelFn();\\n cancelFn = $$rAF(function () {\\n cancelFn = null;\\n fn();\\n nextTick();\\n });\\n };\\n\\n return scheduler;\\n\\n function nextTick() {\\n if (!queue.length) return;\\n var items = queue.shift();\\n\\n for (var i = 0; i < items.length; i++) {\\n items[i]();\\n }\\n\\n if (!cancelFn) {\\n $$rAF(function () {\\n if (!cancelFn) nextTick();\\n });\\n }\\n }\\n }];\\n /**\\r\\n * @ngdoc directive\\r\\n * @name ngAnimateChildren\\r\\n * @restrict AE\\r\\n * @element ANY\\r\\n *\\r\\n * @description\\r\\n *\\r\\n * ngAnimateChildren allows you to specify that children of this element should animate even if any\\r\\n * of the children's parents are currently animating. By default, when an element has an active `enter`, `leave`, or `move`\\r\\n * (structural) animation, child elements that also have an active structural animation are not animated.\\r\\n *\\r\\n * Note that even if `ngAnimteChildren` is set, no child animations will run when the parent element is removed from the DOM (`leave` animation).\\r\\n *\\r\\n *\\r\\n * @param {string} ngAnimateChildren If the value is empty, `true` or `on`,\\r\\n * then child animations are allowed. If the value is `false`, child animations are not allowed.\\r\\n *\\r\\n * @example\\r\\n * \\r\\n \\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n
\\r\\n List of items:\\r\\n
Item {{item}}
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n .container.ng-enter,\\r\\n .container.ng-leave {\\r\\n transition: all ease 1.5s;\\r\\n }\\r\\n \\r\\n .container.ng-enter,\\r\\n .container.ng-leave-active {\\r\\n opacity: 0;\\r\\n }\\r\\n \\r\\n .container.ng-leave,\\r\\n .container.ng-enter-active {\\r\\n opacity: 1;\\r\\n }\\r\\n \\r\\n .item {\\r\\n background: firebrick;\\r\\n color: #FFF;\\r\\n margin-bottom: 10px;\\r\\n }\\r\\n \\r\\n .item.ng-enter,\\r\\n .item.ng-leave {\\r\\n transition: transform 1.5s ease;\\r\\n }\\r\\n \\r\\n .item.ng-enter {\\r\\n transform: translateX(50px);\\r\\n }\\r\\n \\r\\n .item.ng-enter-active {\\r\\n transform: translateX(0);\\r\\n }\\r\\n \\r\\n \\r\\n angular.module('ngAnimateChildren', ['ngAnimate'])\\r\\n .controller('mainController', function() {\\r\\n this.animateChildren = false;\\r\\n this.enterElement = false;\\r\\n });\\r\\n \\r\\n
\\r\\n */\\n\\n var $$AnimateChildrenDirective = ['$interpolate', function ($interpolate) {\\n return {\\n link: function (scope, element, attrs) {\\n var val = attrs.ngAnimateChildren;\\n\\n if (angular.isString(val) && val.length === 0) {\\n //empty attribute\\n element.data(NG_ANIMATE_CHILDREN_DATA, true);\\n } else {\\n // Interpolate and set the value, so that it is available to\\n // animations that run right after compilation\\n setData($interpolate(val)(scope));\\n attrs.$observe('ngAnimateChildren', setData);\\n }\\n\\n function setData(value) {\\n value = value === 'on' || value === 'true';\\n element.data(NG_ANIMATE_CHILDREN_DATA, value);\\n }\\n }\\n };\\n }];\\n var ANIMATE_TIMER_KEY = '$$animateCss';\\n /**\\r\\n * @ngdoc service\\r\\n * @name $animateCss\\r\\n * @kind object\\r\\n *\\r\\n * @description\\r\\n * The `$animateCss` service is a useful utility to trigger customized CSS-based transitions/keyframes\\r\\n * from a JavaScript-based animation or directly from a directive. The purpose of `$animateCss` is NOT\\r\\n * to side-step how `$animate` and ngAnimate work, but the goal is to allow pre-existing animations or\\r\\n * directives to create more complex animations that can be purely driven using CSS code.\\r\\n *\\r\\n * Note that only browsers that support CSS transitions and/or keyframe animations are capable of\\r\\n * rendering animations triggered via `$animateCss` (bad news for IE9 and lower).\\r\\n *\\r\\n * ## Usage\\r\\n * Once again, `$animateCss` is designed to be used inside of a registered JavaScript animation that\\r\\n * is powered by ngAnimate. It is possible to use `$animateCss` directly inside of a directive, however,\\r\\n * any automatic control over cancelling animations and/or preventing animations from being run on\\r\\n * child elements will not be handled by Angular. For this to work as expected, please use `$animate` to\\r\\n * trigger the animation and then setup a JavaScript animation that injects `$animateCss` to trigger\\r\\n * the CSS animation.\\r\\n *\\r\\n * The example below shows how we can create a folding animation on an element using `ng-if`:\\r\\n *\\r\\n * ```html\\r\\n * \\r\\n *
\\r\\n * This element will go BOOM\\r\\n *
\\r\\n * \\r\\n * ```\\r\\n *\\r\\n * Now we create the **JavaScript animation** that will trigger the CSS transition:\\r\\n *\\r\\n * ```js\\r\\n * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\\r\\n * return {\\r\\n * enter: function(element, doneFn) {\\r\\n * var height = element[0].offsetHeight;\\r\\n * return $animateCss(element, {\\r\\n * from: { height:'0px' },\\r\\n * to: { height:height + 'px' },\\r\\n * duration: 1 // one second\\r\\n * });\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * ## More Advanced Uses\\r\\n *\\r\\n * `$animateCss` is the underlying code that ngAnimate uses to power **CSS-based animations** behind the scenes. Therefore CSS hooks\\r\\n * like `.ng-EVENT`, `.ng-EVENT-active`, `.ng-EVENT-stagger` are all features that can be triggered using `$animateCss` via JavaScript code.\\r\\n *\\r\\n * This also means that just about any combination of adding classes, removing classes, setting styles, dynamically setting a keyframe animation,\\r\\n * applying a hardcoded duration or delay value, changing the animation easing or applying a stagger animation are all options that work with\\r\\n * `$animateCss`. The service itself is smart enough to figure out the combination of options and examine the element styling properties in order\\r\\n * to provide a working animation that will run in CSS.\\r\\n *\\r\\n * The example below showcases a more advanced version of the `.fold-animation` from the example above:\\r\\n *\\r\\n * ```js\\r\\n * ngModule.animation('.fold-animation', ['$animateCss', function($animateCss) {\\r\\n * return {\\r\\n * enter: function(element, doneFn) {\\r\\n * var height = element[0].offsetHeight;\\r\\n * return $animateCss(element, {\\r\\n * addClass: 'red large-text pulse-twice',\\r\\n * easing: 'ease-out',\\r\\n * from: { height:'0px' },\\r\\n * to: { height:height + 'px' },\\r\\n * duration: 1 // one second\\r\\n * });\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * Since we're adding/removing CSS classes then the CSS transition will also pick those up:\\r\\n *\\r\\n * ```css\\r\\n * /* since a hardcoded duration value of 1 was provided in the JavaScript animation code,\\r\\n * the CSS classes below will be transitioned despite them being defined as regular CSS classes */\\r\\n * .red { background:red; }\\r\\n * .large-text { font-size:20px; }\\r\\n *\\r\\n * /* we can also use a keyframe animation and $animateCss will make it work alongside the transition */\\r\\n * .pulse-twice {\\r\\n * animation: 0.5s pulse linear 2;\\r\\n * -webkit-animation: 0.5s pulse linear 2;\\r\\n * }\\r\\n *\\r\\n * @keyframes pulse {\\r\\n * from { transform: scale(0.5); }\\r\\n * to { transform: scale(1.5); }\\r\\n * }\\r\\n *\\r\\n * @-webkit-keyframes pulse {\\r\\n * from { -webkit-transform: scale(0.5); }\\r\\n * to { -webkit-transform: scale(1.5); }\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * Given this complex combination of CSS classes, styles and options, `$animateCss` will figure everything out and make the animation happen.\\r\\n *\\r\\n * ## How the Options are handled\\r\\n *\\r\\n * `$animateCss` is very versatile and intelligent when it comes to figuring out what configurations to apply to the element to ensure the animation\\r\\n * works with the options provided. Say for example we were adding a class that contained a keyframe value and we wanted to also animate some inline\\r\\n * styles using the `from` and `to` properties.\\r\\n *\\r\\n * ```js\\r\\n * var animator = $animateCss(element, {\\r\\n * from: { background:'red' },\\r\\n * to: { background:'blue' }\\r\\n * });\\r\\n * animator.start();\\r\\n * ```\\r\\n *\\r\\n * ```css\\r\\n * .rotating-animation {\\r\\n * animation:0.5s rotate linear;\\r\\n * -webkit-animation:0.5s rotate linear;\\r\\n * }\\r\\n *\\r\\n * @keyframes rotate {\\r\\n * from { transform: rotate(0deg); }\\r\\n * to { transform: rotate(360deg); }\\r\\n * }\\r\\n *\\r\\n * @-webkit-keyframes rotate {\\r\\n * from { -webkit-transform: rotate(0deg); }\\r\\n * to { -webkit-transform: rotate(360deg); }\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * The missing pieces here are that we do not have a transition set (within the CSS code nor within the `$animateCss` options) and the duration of the animation is\\r\\n * going to be detected from what the keyframe styles on the CSS class are. In this event, `$animateCss` will automatically create an inline transition\\r\\n * style matching the duration detected from the keyframe style (which is present in the CSS class that is being added) and then prepare both the transition\\r\\n * and keyframe animations to run in parallel on the element. Then when the animation is underway the provided `from` and `to` CSS styles will be applied\\r\\n * and spread across the transition and keyframe animation.\\r\\n *\\r\\n * ## What is returned\\r\\n *\\r\\n * `$animateCss` works in two stages: a preparation phase and an animation phase. Therefore when `$animateCss` is first called it will NOT actually\\r\\n * start the animation. All that is going on here is that the element is being prepared for the animation (which means that the generated CSS classes are\\r\\n * added and removed on the element). Once `$animateCss` is called it will return an object with the following properties:\\r\\n *\\r\\n * ```js\\r\\n * var animator = $animateCss(element, { ... });\\r\\n * ```\\r\\n *\\r\\n * Now what do the contents of our `animator` variable look like:\\r\\n *\\r\\n * ```js\\r\\n * {\\r\\n * // starts the animation\\r\\n * start: Function,\\r\\n *\\r\\n * // ends (aborts) the animation\\r\\n * end: Function\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * To actually start the animation we need to run `animation.start()` which will then return a promise that we can hook into to detect when the animation ends.\\r\\n * If we choose not to run the animation then we MUST run `animation.end()` to perform a cleanup on the element (since some CSS classes and styles may have been\\r\\n * applied to the element during the preparation phase). Note that all other properties such as duration, delay, transitions and keyframes are just properties\\r\\n * and that changing them will not reconfigure the parameters of the animation.\\r\\n *\\r\\n * ### runner.done() vs runner.then()\\r\\n * It is documented that `animation.start()` will return a promise object and this is true, however, there is also an additional method available on the\\r\\n * runner called `.done(callbackFn)`. The done method works the same as `.finally(callbackFn)`, however, it does **not trigger a digest to occur**.\\r\\n * Therefore, for performance reasons, it's always best to use `runner.done(callback)` instead of `runner.then()`, `runner.catch()` or `runner.finally()`\\r\\n * unless you really need a digest to kick off afterwards.\\r\\n *\\r\\n * Keep in mind that, to make this easier, ngAnimate has tweaked the JS animations API to recognize when a runner instance is returned from $animateCss\\r\\n * (so there is no need to call `runner.done(doneFn)` inside of your JavaScript animation code).\\r\\n * Check the {@link ngAnimate.$animateCss#usage animation code above} to see how this works.\\r\\n *\\r\\n * @param {DOMElement} element the element that will be animated\\r\\n * @param {object} options the animation-related options that will be applied during the animation\\r\\n *\\r\\n * * `event` - The DOM event (e.g. enter, leave, move). When used, a generated CSS class of `ng-EVENT` and `ng-EVENT-active` will be applied\\r\\n * to the element during the animation. Multiple events can be provided when spaces are used as a separator. (Note that this will not perform any DOM operation.)\\r\\n * * `structural` - Indicates that the `ng-` prefix will be added to the event class. Setting to `false` or omitting will turn `ng-EVENT` and\\r\\n * `ng-EVENT-active` in `EVENT` and `EVENT-active`. Unused if `event` is omitted.\\r\\n * * `easing` - The CSS easing value that will be applied to the transition or keyframe animation (or both).\\r\\n * * `transitionStyle` - The raw CSS transition style that will be used (e.g. `1s linear all`).\\r\\n * * `keyframeStyle` - The raw CSS keyframe animation style that will be used (e.g. `1s my_animation linear`).\\r\\n * * `from` - The starting CSS styles (a key/value object) that will be applied at the start of the animation.\\r\\n * * `to` - The ending CSS styles (a key/value object) that will be applied across the animation via a CSS transition.\\r\\n * * `addClass` - A space separated list of CSS classes that will be added to the element and spread across the animation.\\r\\n * * `removeClass` - A space separated list of CSS classes that will be removed from the element and spread across the animation.\\r\\n * * `duration` - A number value representing the total duration of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `0`\\r\\n * is provided then the animation will be skipped entirely.\\r\\n * * `delay` - A number value representing the total delay of the transition and/or keyframe (note that a value of 1 is 1000ms). If a value of `true` is\\r\\n * used then whatever delay value is detected from the CSS classes will be mirrored on the elements styles (e.g. by setting delay true then the style value\\r\\n * of the element will be `transition-delay: DETECTED_VALUE`). Using `true` is useful when you want the CSS classes and inline styles to all share the same\\r\\n * CSS delay value.\\r\\n * * `stagger` - A numeric time value representing the delay between successively animated elements\\r\\n * ({@link ngAnimate#css-staggering-animations Click here to learn how CSS-based staggering works in ngAnimate.})\\r\\n * * `staggerIndex` - The numeric index representing the stagger item (e.g. a value of 5 is equal to the sixth item in the stagger; therefore when a\\r\\n * `stagger` option value of `0.1` is used then there will be a stagger delay of `600ms`)\\r\\n * * `applyClassesEarly` - Whether or not the classes being added or removed will be used when detecting the animation. This is set by `$animate` when enter/leave/move animations are fired to ensure that the CSS classes are resolved in time. (Note that this will prevent any transitions from occurring on the classes being added and removed.)\\r\\n * * `cleanupStyles` - Whether or not the provided `from` and `to` styles will be removed once\\r\\n * the animation is closed. This is useful for when the styles are used purely for the sake of\\r\\n * the animation and do not have a lasting visual effect on the element (e.g. a collapse and open animation).\\r\\n * By default this value is set to `false`.\\r\\n *\\r\\n * @return {object} an object with start and end methods and details about the animation.\\r\\n *\\r\\n * * `start` - The method to start the animation. This will return a `Promise` when called.\\r\\n * * `end` - This method will cancel the animation and remove all applied CSS classes and styles.\\r\\n */\\n\\n var ONE_SECOND = 1000;\\n var BASE_TEN = 10;\\n var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;\\n var CLOSING_TIME_BUFFER = 1.5;\\n var DETECT_CSS_PROPERTIES = {\\n transitionDuration: TRANSITION_DURATION_PROP,\\n transitionDelay: TRANSITION_DELAY_PROP,\\n transitionProperty: TRANSITION_PROP + PROPERTY_KEY,\\n animationDuration: ANIMATION_DURATION_PROP,\\n animationDelay: ANIMATION_DELAY_PROP,\\n animationIterationCount: ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY\\n };\\n var DETECT_STAGGER_CSS_PROPERTIES = {\\n transitionDuration: TRANSITION_DURATION_PROP,\\n transitionDelay: TRANSITION_DELAY_PROP,\\n animationDuration: ANIMATION_DURATION_PROP,\\n animationDelay: ANIMATION_DELAY_PROP\\n };\\n\\n function getCssKeyframeDurationStyle(duration) {\\n return [ANIMATION_DURATION_PROP, duration + 's'];\\n }\\n\\n function getCssDelayStyle(delay, isKeyframeAnimation) {\\n var prop = isKeyframeAnimation ? ANIMATION_DELAY_PROP : TRANSITION_DELAY_PROP;\\n return [prop, delay + 's'];\\n }\\n\\n function computeCssStyles($window, element, properties) {\\n var styles = Object.create(null);\\n var detectedStyles = $window.getComputedStyle(element) || {};\\n forEach(properties, function (formalStyleName, actualStyleName) {\\n var val = detectedStyles[formalStyleName];\\n\\n if (val) {\\n var c = val.charAt(0); // only numerical-based values have a negative sign or digit as the first value\\n\\n if (c === '-' || c === '+' || c >= 0) {\\n val = parseMaxTime(val);\\n } // by setting this to null in the event that the delay is not set or is set directly as 0\\n // then we can still allow for negative values to be used later on and not mistake this\\n // value for being greater than any other negative value.\\n\\n\\n if (val === 0) {\\n val = null;\\n }\\n\\n styles[actualStyleName] = val;\\n }\\n });\\n return styles;\\n }\\n\\n function parseMaxTime(str) {\\n var maxValue = 0;\\n var values = str.split(/\\\\s*,\\\\s*/);\\n forEach(values, function (value) {\\n // it's always safe to consider only second values and omit `ms` values since\\n // getComputedStyle will always handle the conversion for us\\n if (value.charAt(value.length - 1) == 's') {\\n value = value.substring(0, value.length - 1);\\n }\\n\\n value = parseFloat(value) || 0;\\n maxValue = maxValue ? Math.max(value, maxValue) : value;\\n });\\n return maxValue;\\n }\\n\\n function truthyTimingValue(val) {\\n return val === 0 || val != null;\\n }\\n\\n function getCssTransitionDurationStyle(duration, applyOnlyDuration) {\\n var style = TRANSITION_PROP;\\n var value = duration + 's';\\n\\n if (applyOnlyDuration) {\\n style += DURATION_KEY;\\n } else {\\n value += ' linear all';\\n }\\n\\n return [style, value];\\n }\\n\\n function createLocalCacheLookup() {\\n var cache = Object.create(null);\\n return {\\n flush: function () {\\n cache = Object.create(null);\\n },\\n count: function (key) {\\n var entry = cache[key];\\n return entry ? entry.total : 0;\\n },\\n get: function (key) {\\n var entry = cache[key];\\n return entry && entry.value;\\n },\\n put: function (key, value) {\\n if (!cache[key]) {\\n cache[key] = {\\n total: 1,\\n value: value\\n };\\n } else {\\n cache[key].total++;\\n }\\n }\\n };\\n } // we do not reassign an already present style value since\\n // if we detect the style property value again we may be\\n // detecting styles that were added via the `from` styles.\\n // We make use of `isDefined` here since an empty string\\n // or null value (which is what getPropertyValue will return\\n // for a non-existing style) will still be marked as a valid\\n // value for the style (a falsy value implies that the style\\n // is to be removed at the end of the animation). If we had a simple\\n // \\\"OR\\\" statement then it would not be enough to catch that.\\n\\n\\n function registerRestorableStyles(backup, node, properties) {\\n forEach(properties, function (prop) {\\n backup[prop] = isDefined(backup[prop]) ? backup[prop] : node.style.getPropertyValue(prop);\\n });\\n }\\n\\n var $AnimateCssProvider = ['$animateProvider', function ($animateProvider) {\\n var gcsLookup = createLocalCacheLookup();\\n var gcsStaggerLookup = createLocalCacheLookup();\\n this.$get = ['$window', '$$jqLite', '$$AnimateRunner', '$timeout', '$$forceReflow', '$sniffer', '$$rAFScheduler', '$$animateQueue', function ($window, $$jqLite, $$AnimateRunner, $timeout, $$forceReflow, $sniffer, $$rAFScheduler, $$animateQueue) {\\n var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\\n var parentCounter = 0;\\n\\n function gcsHashFn(node, extraClasses) {\\n var KEY = \\\"$$ngAnimateParentKey\\\";\\n var parentNode = node.parentNode;\\n var parentID = parentNode[KEY] || (parentNode[KEY] = ++parentCounter);\\n return parentID + '-' + node.getAttribute('class') + '-' + extraClasses;\\n }\\n\\n function computeCachedCssStyles(node, className, cacheKey, properties) {\\n var timings = gcsLookup.get(cacheKey);\\n\\n if (!timings) {\\n timings = computeCssStyles($window, node, properties);\\n\\n if (timings.animationIterationCount === 'infinite') {\\n timings.animationIterationCount = 1;\\n }\\n } // we keep putting this in multiple times even though the value and the cacheKey are the same\\n // because we're keeping an internal tally of how many duplicate animations are detected.\\n\\n\\n gcsLookup.put(cacheKey, timings);\\n return timings;\\n }\\n\\n function computeCachedCssStaggerStyles(node, className, cacheKey, properties) {\\n var stagger; // if we have one or more existing matches of matching elements\\n // containing the same parent + CSS styles (which is how cacheKey works)\\n // then staggering is possible\\n\\n if (gcsLookup.count(cacheKey) > 0) {\\n stagger = gcsStaggerLookup.get(cacheKey);\\n\\n if (!stagger) {\\n var staggerClassName = pendClasses(className, '-stagger');\\n $$jqLite.addClass(node, staggerClassName);\\n stagger = computeCssStyles($window, node, properties); // force the conversion of a null value to zero incase not set\\n\\n stagger.animationDuration = Math.max(stagger.animationDuration, 0);\\n stagger.transitionDuration = Math.max(stagger.transitionDuration, 0);\\n $$jqLite.removeClass(node, staggerClassName);\\n gcsStaggerLookup.put(cacheKey, stagger);\\n }\\n }\\n\\n return stagger || {};\\n }\\n\\n var cancelLastRAFRequest;\\n var rafWaitQueue = [];\\n\\n function waitUntilQuiet(callback) {\\n rafWaitQueue.push(callback);\\n $$rAFScheduler.waitUntilQuiet(function () {\\n gcsLookup.flush();\\n gcsStaggerLookup.flush(); // DO NOT REMOVE THIS LINE OR REFACTOR OUT THE `pageWidth` variable.\\n // PLEASE EXAMINE THE `$$forceReflow` service to understand why.\\n\\n var pageWidth = $$forceReflow(); // we use a for loop to ensure that if the queue is changed\\n // during this looping then it will consider new requests\\n\\n for (var i = 0; i < rafWaitQueue.length; i++) {\\n rafWaitQueue[i](pageWidth);\\n }\\n\\n rafWaitQueue.length = 0;\\n });\\n }\\n\\n function computeTimings(node, className, cacheKey) {\\n var timings = computeCachedCssStyles(node, className, cacheKey, DETECT_CSS_PROPERTIES);\\n var aD = timings.animationDelay;\\n var tD = timings.transitionDelay;\\n timings.maxDelay = aD && tD ? Math.max(aD, tD) : aD || tD;\\n timings.maxDuration = Math.max(timings.animationDuration * timings.animationIterationCount, timings.transitionDuration);\\n return timings;\\n }\\n\\n return function init(element, initialOptions) {\\n // all of the animation functions should create\\n // a copy of the options data, however, if a\\n // parent service has already created a copy then\\n // we should stick to using that\\n var options = initialOptions || {};\\n\\n if (!options.$$prepared) {\\n options = prepareAnimationOptions(copy(options));\\n }\\n\\n var restoreStyles = {};\\n var node = getDomNode(element);\\n\\n if (!node || !node.parentNode || !$$animateQueue.enabled()) {\\n return closeAndReturnNoopAnimator();\\n }\\n\\n var temporaryStyles = [];\\n var classes = element.attr('class');\\n var styles = packageStyles(options);\\n var animationClosed;\\n var animationPaused;\\n var animationCompleted;\\n var runner;\\n var runnerHost;\\n var maxDelay;\\n var maxDelayTime;\\n var maxDuration;\\n var maxDurationTime;\\n var startTime;\\n var events = [];\\n\\n if (options.duration === 0 || !$sniffer.animations && !$sniffer.transitions) {\\n return closeAndReturnNoopAnimator();\\n }\\n\\n var method = options.event && isArray(options.event) ? options.event.join(' ') : options.event;\\n var isStructural = method && options.structural;\\n var structuralClassName = '';\\n var addRemoveClassName = '';\\n\\n if (isStructural) {\\n structuralClassName = pendClasses(method, EVENT_CLASS_PREFIX, true);\\n } else if (method) {\\n structuralClassName = method;\\n }\\n\\n if (options.addClass) {\\n addRemoveClassName += pendClasses(options.addClass, ADD_CLASS_SUFFIX);\\n }\\n\\n if (options.removeClass) {\\n if (addRemoveClassName.length) {\\n addRemoveClassName += ' ';\\n }\\n\\n addRemoveClassName += pendClasses(options.removeClass, REMOVE_CLASS_SUFFIX);\\n } // there may be a situation where a structural animation is combined together\\n // with CSS classes that need to resolve before the animation is computed.\\n // However this means that there is no explicit CSS code to block the animation\\n // from happening (by setting 0s none in the class name). If this is the case\\n // we need to apply the classes before the first rAF so we know to continue if\\n // there actually is a detected transition or keyframe animation\\n\\n\\n if (options.applyClassesEarly && addRemoveClassName.length) {\\n applyAnimationClasses(element, options);\\n }\\n\\n var preparationClasses = [structuralClassName, addRemoveClassName].join(' ').trim();\\n var fullClassName = classes + ' ' + preparationClasses;\\n var activeClasses = pendClasses(preparationClasses, ACTIVE_CLASS_SUFFIX);\\n var hasToStyles = styles.to && Object.keys(styles.to).length > 0;\\n var containsKeyframeAnimation = (options.keyframeStyle || '').length > 0; // there is no way we can trigger an animation if no styles and\\n // no classes are being applied which would then trigger a transition,\\n // unless there a is raw keyframe value that is applied to the element.\\n\\n if (!containsKeyframeAnimation && !hasToStyles && !preparationClasses) {\\n return closeAndReturnNoopAnimator();\\n }\\n\\n var cacheKey, stagger;\\n\\n if (options.stagger > 0) {\\n var staggerVal = parseFloat(options.stagger);\\n stagger = {\\n transitionDelay: staggerVal,\\n animationDelay: staggerVal,\\n transitionDuration: 0,\\n animationDuration: 0\\n };\\n } else {\\n cacheKey = gcsHashFn(node, fullClassName);\\n stagger = computeCachedCssStaggerStyles(node, preparationClasses, cacheKey, DETECT_STAGGER_CSS_PROPERTIES);\\n }\\n\\n if (!options.$$skipPreparationClasses) {\\n $$jqLite.addClass(element, preparationClasses);\\n }\\n\\n var applyOnlyDuration;\\n\\n if (options.transitionStyle) {\\n var transitionStyle = [TRANSITION_PROP, options.transitionStyle];\\n applyInlineStyle(node, transitionStyle);\\n temporaryStyles.push(transitionStyle);\\n }\\n\\n if (options.duration >= 0) {\\n applyOnlyDuration = node.style[TRANSITION_PROP].length > 0;\\n var durationStyle = getCssTransitionDurationStyle(options.duration, applyOnlyDuration); // we set the duration so that it will be picked up by getComputedStyle later\\n\\n applyInlineStyle(node, durationStyle);\\n temporaryStyles.push(durationStyle);\\n }\\n\\n if (options.keyframeStyle) {\\n var keyframeStyle = [ANIMATION_PROP, options.keyframeStyle];\\n applyInlineStyle(node, keyframeStyle);\\n temporaryStyles.push(keyframeStyle);\\n }\\n\\n var itemIndex = stagger ? options.staggerIndex >= 0 ? options.staggerIndex : gcsLookup.count(cacheKey) : 0;\\n var isFirst = itemIndex === 0; // this is a pre-emptive way of forcing the setup classes to be added and applied INSTANTLY\\n // without causing any combination of transitions to kick in. By adding a negative delay value\\n // it forces the setup class' transition to end immediately. We later then remove the negative\\n // transition delay to allow for the transition to naturally do it's thing. The beauty here is\\n // that if there is no transition defined then nothing will happen and this will also allow\\n // other transitions to be stacked on top of each other without any chopping them out.\\n\\n if (isFirst && !options.skipBlocking) {\\n blockTransitions(node, SAFE_FAST_FORWARD_DURATION_VALUE);\\n }\\n\\n var timings = computeTimings(node, fullClassName, cacheKey);\\n var relativeDelay = timings.maxDelay;\\n maxDelay = Math.max(relativeDelay, 0);\\n maxDuration = timings.maxDuration;\\n var flags = {};\\n flags.hasTransitions = timings.transitionDuration > 0;\\n flags.hasAnimations = timings.animationDuration > 0;\\n flags.hasTransitionAll = flags.hasTransitions && timings.transitionProperty == 'all';\\n flags.applyTransitionDuration = hasToStyles && (flags.hasTransitions && !flags.hasTransitionAll || flags.hasAnimations && !flags.hasTransitions);\\n flags.applyAnimationDuration = options.duration && flags.hasAnimations;\\n flags.applyTransitionDelay = truthyTimingValue(options.delay) && (flags.applyTransitionDuration || flags.hasTransitions);\\n flags.applyAnimationDelay = truthyTimingValue(options.delay) && flags.hasAnimations;\\n flags.recalculateTimingStyles = addRemoveClassName.length > 0;\\n\\n if (flags.applyTransitionDuration || flags.applyAnimationDuration) {\\n maxDuration = options.duration ? parseFloat(options.duration) : maxDuration;\\n\\n if (flags.applyTransitionDuration) {\\n flags.hasTransitions = true;\\n timings.transitionDuration = maxDuration;\\n applyOnlyDuration = node.style[TRANSITION_PROP + PROPERTY_KEY].length > 0;\\n temporaryStyles.push(getCssTransitionDurationStyle(maxDuration, applyOnlyDuration));\\n }\\n\\n if (flags.applyAnimationDuration) {\\n flags.hasAnimations = true;\\n timings.animationDuration = maxDuration;\\n temporaryStyles.push(getCssKeyframeDurationStyle(maxDuration));\\n }\\n }\\n\\n if (maxDuration === 0 && !flags.recalculateTimingStyles) {\\n return closeAndReturnNoopAnimator();\\n }\\n\\n if (options.delay != null) {\\n var delayStyle;\\n\\n if (typeof options.delay !== \\\"boolean\\\") {\\n delayStyle = parseFloat(options.delay); // number in options.delay means we have to recalculate the delay for the closing timeout\\n\\n maxDelay = Math.max(delayStyle, 0);\\n }\\n\\n if (flags.applyTransitionDelay) {\\n temporaryStyles.push(getCssDelayStyle(delayStyle));\\n }\\n\\n if (flags.applyAnimationDelay) {\\n temporaryStyles.push(getCssDelayStyle(delayStyle, true));\\n }\\n } // we need to recalculate the delay value since we used a pre-emptive negative\\n // delay value and the delay value is required for the final event checking. This\\n // property will ensure that this will happen after the RAF phase has passed.\\n\\n\\n if (options.duration == null && timings.transitionDuration > 0) {\\n flags.recalculateTimingStyles = flags.recalculateTimingStyles || isFirst;\\n }\\n\\n maxDelayTime = maxDelay * ONE_SECOND;\\n maxDurationTime = maxDuration * ONE_SECOND;\\n\\n if (!options.skipBlocking) {\\n flags.blockTransition = timings.transitionDuration > 0;\\n flags.blockKeyframeAnimation = timings.animationDuration > 0 && stagger.animationDelay > 0 && stagger.animationDuration === 0;\\n }\\n\\n if (options.from) {\\n if (options.cleanupStyles) {\\n registerRestorableStyles(restoreStyles, node, Object.keys(options.from));\\n }\\n\\n applyAnimationFromStyles(element, options);\\n }\\n\\n if (flags.blockTransition || flags.blockKeyframeAnimation) {\\n applyBlocking(maxDuration);\\n } else if (!options.skipBlocking) {\\n blockTransitions(node, false);\\n } // TODO(matsko): for 1.5 change this code to have an animator object for better debugging\\n\\n\\n return {\\n $$willAnimate: true,\\n end: endFn,\\n start: function () {\\n if (animationClosed) return;\\n runnerHost = {\\n end: endFn,\\n cancel: cancelFn,\\n resume: null,\\n //this will be set during the start() phase\\n pause: null\\n };\\n runner = new $$AnimateRunner(runnerHost);\\n waitUntilQuiet(start); // we don't have access to pause/resume the animation\\n // since it hasn't run yet. AnimateRunner will therefore\\n // set noop functions for resume and pause and they will\\n // later be overridden once the animation is triggered\\n\\n return runner;\\n }\\n };\\n\\n function endFn() {\\n close();\\n }\\n\\n function cancelFn() {\\n close(true);\\n }\\n\\n function close(rejected) {\\n // jshint ignore:line\\n // if the promise has been called already then we shouldn't close\\n // the animation again\\n if (animationClosed || animationCompleted && animationPaused) return;\\n animationClosed = true;\\n animationPaused = false;\\n\\n if (!options.$$skipPreparationClasses) {\\n $$jqLite.removeClass(element, preparationClasses);\\n }\\n\\n $$jqLite.removeClass(element, activeClasses);\\n blockKeyframeAnimations(node, false);\\n blockTransitions(node, false);\\n forEach(temporaryStyles, function (entry) {\\n // There is only one way to remove inline style properties entirely from elements.\\n // By using `removeProperty` this works, but we need to convert camel-cased CSS\\n // styles down to hyphenated values.\\n node.style[entry[0]] = '';\\n });\\n applyAnimationClasses(element, options);\\n applyAnimationStyles(element, options);\\n\\n if (Object.keys(restoreStyles).length) {\\n forEach(restoreStyles, function (value, prop) {\\n value ? node.style.setProperty(prop, value) : node.style.removeProperty(prop);\\n });\\n } // the reason why we have this option is to allow a synchronous closing callback\\n // that is fired as SOON as the animation ends (when the CSS is removed) or if\\n // the animation never takes off at all. A good example is a leave animation since\\n // the element must be removed just after the animation is over or else the element\\n // will appear on screen for one animation frame causing an overbearing flicker.\\n\\n\\n if (options.onDone) {\\n options.onDone();\\n }\\n\\n if (events && events.length) {\\n // Remove the transitionend / animationend listener(s)\\n element.off(events.join(' '), onAnimationProgress);\\n } //Cancel the fallback closing timeout and remove the timer data\\n\\n\\n var animationTimerData = element.data(ANIMATE_TIMER_KEY);\\n\\n if (animationTimerData) {\\n $timeout.cancel(animationTimerData[0].timer);\\n element.removeData(ANIMATE_TIMER_KEY);\\n } // if the preparation function fails then the promise is not setup\\n\\n\\n if (runner) {\\n runner.complete(!rejected);\\n }\\n }\\n\\n function applyBlocking(duration) {\\n if (flags.blockTransition) {\\n blockTransitions(node, duration);\\n }\\n\\n if (flags.blockKeyframeAnimation) {\\n blockKeyframeAnimations(node, !!duration);\\n }\\n }\\n\\n function closeAndReturnNoopAnimator() {\\n runner = new $$AnimateRunner({\\n end: endFn,\\n cancel: cancelFn\\n }); // should flush the cache animation\\n\\n waitUntilQuiet(noop);\\n close();\\n return {\\n $$willAnimate: false,\\n start: function () {\\n return runner;\\n },\\n end: endFn\\n };\\n }\\n\\n function onAnimationProgress(event) {\\n event.stopPropagation();\\n var ev = event.originalEvent || event; // we now always use `Date.now()` due to the recent changes with\\n // event.timeStamp in Firefox, Webkit and Chrome (see #13494 for more info)\\n\\n var timeStamp = ev.$manualTimeStamp || Date.now();\\n /* Firefox (or possibly just Gecko) likes to not round values up\\r\\n * when a ms measurement is used for the animation */\\n\\n var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));\\n /* $manualTimeStamp is a mocked timeStamp value which is set\\r\\n * within browserTrigger(). This is only here so that tests can\\r\\n * mock animations properly. Real events fallback to event.timeStamp,\\r\\n * or, if they don't, then a timeStamp is automatically created for them.\\r\\n * We're checking to see if the timeStamp surpasses the expected delay,\\r\\n * but we're using elapsedTime instead of the timeStamp on the 2nd\\r\\n * pre-condition since animationPauseds sometimes close off early */\\n\\n if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {\\n // we set this flag to ensure that if the transition is paused then, when resumed,\\n // the animation will automatically close itself since transitions cannot be paused.\\n animationCompleted = true;\\n close();\\n }\\n }\\n\\n function start() {\\n if (animationClosed) return;\\n\\n if (!node.parentNode) {\\n close();\\n return;\\n } // even though we only pause keyframe animations here the pause flag\\n // will still happen when transitions are used. Only the transition will\\n // not be paused since that is not possible. If the animation ends when\\n // paused then it will not complete until unpaused or cancelled.\\n\\n\\n var playPause = function (playAnimation) {\\n if (!animationCompleted) {\\n animationPaused = !playAnimation;\\n\\n if (timings.animationDuration) {\\n var value = blockKeyframeAnimations(node, animationPaused);\\n animationPaused ? temporaryStyles.push(value) : removeFromArray(temporaryStyles, value);\\n }\\n } else if (animationPaused && playAnimation) {\\n animationPaused = false;\\n close();\\n }\\n }; // checking the stagger duration prevents an accidentally cascade of the CSS delay style\\n // being inherited from the parent. If the transition duration is zero then we can safely\\n // rely that the delay value is an intentional stagger delay style.\\n\\n\\n var maxStagger = itemIndex > 0 && (timings.transitionDuration && stagger.transitionDuration === 0 || timings.animationDuration && stagger.animationDuration === 0) && Math.max(stagger.animationDelay, stagger.transitionDelay);\\n\\n if (maxStagger) {\\n $timeout(triggerAnimationStart, Math.floor(maxStagger * itemIndex * ONE_SECOND), false);\\n } else {\\n triggerAnimationStart();\\n } // this will decorate the existing promise runner with pause/resume methods\\n\\n\\n runnerHost.resume = function () {\\n playPause(true);\\n };\\n\\n runnerHost.pause = function () {\\n playPause(false);\\n };\\n\\n function triggerAnimationStart() {\\n // just incase a stagger animation kicks in when the animation\\n // itself was cancelled entirely\\n if (animationClosed) return;\\n applyBlocking(false);\\n forEach(temporaryStyles, function (entry) {\\n var key = entry[0];\\n var value = entry[1];\\n node.style[key] = value;\\n });\\n applyAnimationClasses(element, options);\\n $$jqLite.addClass(element, activeClasses);\\n\\n if (flags.recalculateTimingStyles) {\\n fullClassName = node.className + ' ' + preparationClasses;\\n cacheKey = gcsHashFn(node, fullClassName);\\n timings = computeTimings(node, fullClassName, cacheKey);\\n relativeDelay = timings.maxDelay;\\n maxDelay = Math.max(relativeDelay, 0);\\n maxDuration = timings.maxDuration;\\n\\n if (maxDuration === 0) {\\n close();\\n return;\\n }\\n\\n flags.hasTransitions = timings.transitionDuration > 0;\\n flags.hasAnimations = timings.animationDuration > 0;\\n }\\n\\n if (flags.applyAnimationDelay) {\\n relativeDelay = typeof options.delay !== \\\"boolean\\\" && truthyTimingValue(options.delay) ? parseFloat(options.delay) : relativeDelay;\\n maxDelay = Math.max(relativeDelay, 0);\\n timings.animationDelay = relativeDelay;\\n delayStyle = getCssDelayStyle(relativeDelay, true);\\n temporaryStyles.push(delayStyle);\\n node.style[delayStyle[0]] = delayStyle[1];\\n }\\n\\n maxDelayTime = maxDelay * ONE_SECOND;\\n maxDurationTime = maxDuration * ONE_SECOND;\\n\\n if (options.easing) {\\n var easeProp,\\n easeVal = options.easing;\\n\\n if (flags.hasTransitions) {\\n easeProp = TRANSITION_PROP + TIMING_KEY;\\n temporaryStyles.push([easeProp, easeVal]);\\n node.style[easeProp] = easeVal;\\n }\\n\\n if (flags.hasAnimations) {\\n easeProp = ANIMATION_PROP + TIMING_KEY;\\n temporaryStyles.push([easeProp, easeVal]);\\n node.style[easeProp] = easeVal;\\n }\\n }\\n\\n if (timings.transitionDuration) {\\n events.push(TRANSITIONEND_EVENT);\\n }\\n\\n if (timings.animationDuration) {\\n events.push(ANIMATIONEND_EVENT);\\n }\\n\\n startTime = Date.now();\\n var timerTime = maxDelayTime + CLOSING_TIME_BUFFER * maxDurationTime;\\n var endTime = startTime + timerTime;\\n var animationsData = element.data(ANIMATE_TIMER_KEY) || [];\\n var setupFallbackTimer = true;\\n\\n if (animationsData.length) {\\n var currentTimerData = animationsData[0];\\n setupFallbackTimer = endTime > currentTimerData.expectedEndTime;\\n\\n if (setupFallbackTimer) {\\n $timeout.cancel(currentTimerData.timer);\\n } else {\\n animationsData.push(close);\\n }\\n }\\n\\n if (setupFallbackTimer) {\\n var timer = $timeout(onAnimationExpired, timerTime, false);\\n animationsData[0] = {\\n timer: timer,\\n expectedEndTime: endTime\\n };\\n animationsData.push(close);\\n element.data(ANIMATE_TIMER_KEY, animationsData);\\n }\\n\\n if (events.length) {\\n element.on(events.join(' '), onAnimationProgress);\\n }\\n\\n if (options.to) {\\n if (options.cleanupStyles) {\\n registerRestorableStyles(restoreStyles, node, Object.keys(options.to));\\n }\\n\\n applyAnimationToStyles(element, options);\\n }\\n }\\n\\n function onAnimationExpired() {\\n var animationsData = element.data(ANIMATE_TIMER_KEY); // this will be false in the event that the element was\\n // removed from the DOM (via a leave animation or something\\n // similar)\\n\\n if (animationsData) {\\n for (var i = 1; i < animationsData.length; i++) {\\n animationsData[i]();\\n }\\n\\n element.removeData(ANIMATE_TIMER_KEY);\\n }\\n }\\n }\\n };\\n }];\\n }];\\n var $$AnimateCssDriverProvider = ['$$animationProvider', function ($$animationProvider) {\\n $$animationProvider.drivers.push('$$animateCssDriver');\\n var NG_ANIMATE_SHIM_CLASS_NAME = 'ng-animate-shim';\\n var NG_ANIMATE_ANCHOR_CLASS_NAME = 'ng-anchor';\\n var NG_OUT_ANCHOR_CLASS_NAME = 'ng-anchor-out';\\n var NG_IN_ANCHOR_CLASS_NAME = 'ng-anchor-in';\\n\\n function isDocumentFragment(node) {\\n return node.parentNode && node.parentNode.nodeType === 11;\\n }\\n\\n this.$get = ['$animateCss', '$rootScope', '$$AnimateRunner', '$rootElement', '$sniffer', '$$jqLite', '$document', function ($animateCss, $rootScope, $$AnimateRunner, $rootElement, $sniffer, $$jqLite, $document) {\\n // only browsers that support these properties can render animations\\n if (!$sniffer.animations && !$sniffer.transitions) return noop;\\n var bodyNode = $document[0].body;\\n var rootNode = getDomNode($rootElement);\\n var rootBodyElement = jqLite( // this is to avoid using something that exists outside of the body\\n // we also special case the doc fragment case because our unit test code\\n // appends the $rootElement to the body after the app has been bootstrapped\\n isDocumentFragment(rootNode) || bodyNode.contains(rootNode) ? rootNode : bodyNode);\\n var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\\n return function initDriverFn(animationDetails) {\\n return animationDetails.from && animationDetails.to ? prepareFromToAnchorAnimation(animationDetails.from, animationDetails.to, animationDetails.classes, animationDetails.anchors) : prepareRegularAnimation(animationDetails);\\n };\\n\\n function filterCssClasses(classes) {\\n //remove all the `ng-` stuff\\n return classes.replace(/\\\\bng-\\\\S+\\\\b/g, '');\\n }\\n\\n function getUniqueValues(a, b) {\\n if (isString(a)) a = a.split(' ');\\n if (isString(b)) b = b.split(' ');\\n return a.filter(function (val) {\\n return b.indexOf(val) === -1;\\n }).join(' ');\\n }\\n\\n function prepareAnchoredAnimation(classes, outAnchor, inAnchor) {\\n var clone = jqLite(getDomNode(outAnchor).cloneNode(true));\\n var startingClasses = filterCssClasses(getClassVal(clone));\\n outAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\\n inAnchor.addClass(NG_ANIMATE_SHIM_CLASS_NAME);\\n clone.addClass(NG_ANIMATE_ANCHOR_CLASS_NAME);\\n rootBodyElement.append(clone);\\n var animatorIn,\\n animatorOut = prepareOutAnimation(); // the user may not end up using the `out` animation and\\n // only making use of the `in` animation or vice-versa.\\n // In either case we should allow this and not assume the\\n // animation is over unless both animations are not used.\\n\\n if (!animatorOut) {\\n animatorIn = prepareInAnimation();\\n\\n if (!animatorIn) {\\n return end();\\n }\\n }\\n\\n var startingAnimator = animatorOut || animatorIn;\\n return {\\n start: function () {\\n var runner;\\n var currentAnimation = startingAnimator.start();\\n currentAnimation.done(function () {\\n currentAnimation = null;\\n\\n if (!animatorIn) {\\n animatorIn = prepareInAnimation();\\n\\n if (animatorIn) {\\n currentAnimation = animatorIn.start();\\n currentAnimation.done(function () {\\n currentAnimation = null;\\n end();\\n runner.complete();\\n });\\n return currentAnimation;\\n }\\n } // in the event that there is no `in` animation\\n\\n\\n end();\\n runner.complete();\\n });\\n runner = new $$AnimateRunner({\\n end: endFn,\\n cancel: endFn\\n });\\n return runner;\\n\\n function endFn() {\\n if (currentAnimation) {\\n currentAnimation.end();\\n }\\n }\\n }\\n };\\n\\n function calculateAnchorStyles(anchor) {\\n var styles = {};\\n var coords = getDomNode(anchor).getBoundingClientRect(); // we iterate directly since safari messes up and doesn't return\\n // all the keys for the coords object when iterated\\n\\n forEach(['width', 'height', 'top', 'left'], function (key) {\\n var value = coords[key];\\n\\n switch (key) {\\n case 'top':\\n value += bodyNode.scrollTop;\\n break;\\n\\n case 'left':\\n value += bodyNode.scrollLeft;\\n break;\\n }\\n\\n styles[key] = Math.floor(value) + 'px';\\n });\\n return styles;\\n }\\n\\n function prepareOutAnimation() {\\n var animator = $animateCss(clone, {\\n addClass: NG_OUT_ANCHOR_CLASS_NAME,\\n delay: true,\\n from: calculateAnchorStyles(outAnchor)\\n }); // read the comment within `prepareRegularAnimation` to understand\\n // why this check is necessary\\n\\n return animator.$$willAnimate ? animator : null;\\n }\\n\\n function getClassVal(element) {\\n return element.attr('class') || '';\\n }\\n\\n function prepareInAnimation() {\\n var endingClasses = filterCssClasses(getClassVal(inAnchor));\\n var toAdd = getUniqueValues(endingClasses, startingClasses);\\n var toRemove = getUniqueValues(startingClasses, endingClasses);\\n var animator = $animateCss(clone, {\\n to: calculateAnchorStyles(inAnchor),\\n addClass: NG_IN_ANCHOR_CLASS_NAME + ' ' + toAdd,\\n removeClass: NG_OUT_ANCHOR_CLASS_NAME + ' ' + toRemove,\\n delay: true\\n }); // read the comment within `prepareRegularAnimation` to understand\\n // why this check is necessary\\n\\n return animator.$$willAnimate ? animator : null;\\n }\\n\\n function end() {\\n clone.remove();\\n outAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\\n inAnchor.removeClass(NG_ANIMATE_SHIM_CLASS_NAME);\\n }\\n }\\n\\n function prepareFromToAnchorAnimation(from, to, classes, anchors) {\\n var fromAnimation = prepareRegularAnimation(from, noop);\\n var toAnimation = prepareRegularAnimation(to, noop);\\n var anchorAnimations = [];\\n forEach(anchors, function (anchor) {\\n var outElement = anchor['out'];\\n var inElement = anchor['in'];\\n var animator = prepareAnchoredAnimation(classes, outElement, inElement);\\n\\n if (animator) {\\n anchorAnimations.push(animator);\\n }\\n }); // no point in doing anything when there are no elements to animate\\n\\n if (!fromAnimation && !toAnimation && anchorAnimations.length === 0) return;\\n return {\\n start: function () {\\n var animationRunners = [];\\n\\n if (fromAnimation) {\\n animationRunners.push(fromAnimation.start());\\n }\\n\\n if (toAnimation) {\\n animationRunners.push(toAnimation.start());\\n }\\n\\n forEach(anchorAnimations, function (animation) {\\n animationRunners.push(animation.start());\\n });\\n var runner = new $$AnimateRunner({\\n end: endFn,\\n cancel: endFn // CSS-driven animations cannot be cancelled, only ended\\n\\n });\\n $$AnimateRunner.all(animationRunners, function (status) {\\n runner.complete(status);\\n });\\n return runner;\\n\\n function endFn() {\\n forEach(animationRunners, function (runner) {\\n runner.end();\\n });\\n }\\n }\\n };\\n }\\n\\n function prepareRegularAnimation(animationDetails) {\\n var element = animationDetails.element;\\n var options = animationDetails.options || {};\\n\\n if (animationDetails.structural) {\\n options.event = animationDetails.event;\\n options.structural = true;\\n options.applyClassesEarly = true; // we special case the leave animation since we want to ensure that\\n // the element is removed as soon as the animation is over. Otherwise\\n // a flicker might appear or the element may not be removed at all\\n\\n if (animationDetails.event === 'leave') {\\n options.onDone = options.domOperation;\\n }\\n } // We assign the preparationClasses as the actual animation event since\\n // the internals of $animateCss will just suffix the event token values\\n // with `-active` to trigger the animation.\\n\\n\\n if (options.preparationClasses) {\\n options.event = concatWithSpace(options.event, options.preparationClasses);\\n }\\n\\n var animator = $animateCss(element, options); // the driver lookup code inside of $$animation attempts to spawn a\\n // driver one by one until a driver returns a.$$willAnimate animator object.\\n // $animateCss will always return an object, however, it will pass in\\n // a flag as a hint as to whether an animation was detected or not\\n\\n return animator.$$willAnimate ? animator : null;\\n }\\n }];\\n }]; // TODO(matsko): use caching here to speed things up for detection\\n // TODO(matsko): add documentation\\n // by the time...\\n\\n var $$AnimateJsProvider = ['$animateProvider', function ($animateProvider) {\\n this.$get = ['$injector', '$$AnimateRunner', '$$jqLite', function ($injector, $$AnimateRunner, $$jqLite) {\\n var applyAnimationClasses = applyAnimationClassesFactory($$jqLite); // $animateJs(element, 'enter');\\n\\n return function (element, event, classes, options) {\\n var animationClosed = false; // the `classes` argument is optional and if it is not used\\n // then the classes will be resolved from the element's className\\n // property as well as options.addClass/options.removeClass.\\n\\n if (arguments.length === 3 && isObject(classes)) {\\n options = classes;\\n classes = null;\\n }\\n\\n options = prepareAnimationOptions(options);\\n\\n if (!classes) {\\n classes = element.attr('class') || '';\\n\\n if (options.addClass) {\\n classes += ' ' + options.addClass;\\n }\\n\\n if (options.removeClass) {\\n classes += ' ' + options.removeClass;\\n }\\n }\\n\\n var classesToAdd = options.addClass;\\n var classesToRemove = options.removeClass; // the lookupAnimations function returns a series of animation objects that are\\n // matched up with one or more of the CSS classes. These animation objects are\\n // defined via the module.animation factory function. If nothing is detected then\\n // we don't return anything which then makes $animation query the next driver.\\n\\n var animations = lookupAnimations(classes);\\n var before, after;\\n\\n if (animations.length) {\\n var afterFn, beforeFn;\\n\\n if (event == 'leave') {\\n beforeFn = 'leave';\\n afterFn = 'afterLeave'; // TODO(matsko): get rid of this\\n } else {\\n beforeFn = 'before' + event.charAt(0).toUpperCase() + event.substr(1);\\n afterFn = event;\\n }\\n\\n if (event !== 'enter' && event !== 'move') {\\n before = packageAnimations(element, event, options, animations, beforeFn);\\n }\\n\\n after = packageAnimations(element, event, options, animations, afterFn);\\n } // no matching animations\\n\\n\\n if (!before && !after) return;\\n\\n function applyOptions() {\\n options.domOperation();\\n applyAnimationClasses(element, options);\\n }\\n\\n function close() {\\n animationClosed = true;\\n applyOptions();\\n applyAnimationStyles(element, options);\\n }\\n\\n var runner;\\n return {\\n $$willAnimate: true,\\n end: function () {\\n if (runner) {\\n runner.end();\\n } else {\\n close();\\n runner = new $$AnimateRunner();\\n runner.complete(true);\\n }\\n\\n return runner;\\n },\\n start: function () {\\n if (runner) {\\n return runner;\\n }\\n\\n runner = new $$AnimateRunner();\\n var closeActiveAnimations;\\n var chain = [];\\n\\n if (before) {\\n chain.push(function (fn) {\\n closeActiveAnimations = before(fn);\\n });\\n }\\n\\n if (chain.length) {\\n chain.push(function (fn) {\\n applyOptions();\\n fn(true);\\n });\\n } else {\\n applyOptions();\\n }\\n\\n if (after) {\\n chain.push(function (fn) {\\n closeActiveAnimations = after(fn);\\n });\\n }\\n\\n runner.setHost({\\n end: function () {\\n endAnimations();\\n },\\n cancel: function () {\\n endAnimations(true);\\n }\\n });\\n $$AnimateRunner.chain(chain, onComplete);\\n return runner;\\n\\n function onComplete(success) {\\n close(success);\\n runner.complete(success);\\n }\\n\\n function endAnimations(cancelled) {\\n if (!animationClosed) {\\n (closeActiveAnimations || noop)(cancelled);\\n onComplete(cancelled);\\n }\\n }\\n }\\n };\\n\\n function executeAnimationFn(fn, element, event, options, onDone) {\\n var args;\\n\\n switch (event) {\\n case 'animate':\\n args = [element, options.from, options.to, onDone];\\n break;\\n\\n case 'setClass':\\n args = [element, classesToAdd, classesToRemove, onDone];\\n break;\\n\\n case 'addClass':\\n args = [element, classesToAdd, onDone];\\n break;\\n\\n case 'removeClass':\\n args = [element, classesToRemove, onDone];\\n break;\\n\\n default:\\n args = [element, onDone];\\n break;\\n }\\n\\n args.push(options);\\n var value = fn.apply(fn, args);\\n\\n if (value) {\\n if (isFunction(value.start)) {\\n value = value.start();\\n }\\n\\n if (value instanceof $$AnimateRunner) {\\n value.done(onDone);\\n } else if (isFunction(value)) {\\n // optional onEnd / onCancel callback\\n return value;\\n }\\n }\\n\\n return noop;\\n }\\n\\n function groupEventedAnimations(element, event, options, animations, fnName) {\\n var operations = [];\\n forEach(animations, function (ani) {\\n var animation = ani[fnName];\\n if (!animation) return; // note that all of these animations will run in parallel\\n\\n operations.push(function () {\\n var runner;\\n var endProgressCb;\\n var resolved = false;\\n\\n var onAnimationComplete = function (rejected) {\\n if (!resolved) {\\n resolved = true;\\n (endProgressCb || noop)(rejected);\\n runner.complete(!rejected);\\n }\\n };\\n\\n runner = new $$AnimateRunner({\\n end: function () {\\n onAnimationComplete();\\n },\\n cancel: function () {\\n onAnimationComplete(true);\\n }\\n });\\n endProgressCb = executeAnimationFn(animation, element, event, options, function (result) {\\n var cancelled = result === false;\\n onAnimationComplete(cancelled);\\n });\\n return runner;\\n });\\n });\\n return operations;\\n }\\n\\n function packageAnimations(element, event, options, animations, fnName) {\\n var operations = groupEventedAnimations(element, event, options, animations, fnName);\\n\\n if (operations.length === 0) {\\n var a, b;\\n\\n if (fnName === 'beforeSetClass') {\\n a = groupEventedAnimations(element, 'removeClass', options, animations, 'beforeRemoveClass');\\n b = groupEventedAnimations(element, 'addClass', options, animations, 'beforeAddClass');\\n } else if (fnName === 'setClass') {\\n a = groupEventedAnimations(element, 'removeClass', options, animations, 'removeClass');\\n b = groupEventedAnimations(element, 'addClass', options, animations, 'addClass');\\n }\\n\\n if (a) {\\n operations = operations.concat(a);\\n }\\n\\n if (b) {\\n operations = operations.concat(b);\\n }\\n }\\n\\n if (operations.length === 0) return; // TODO(matsko): add documentation\\n\\n return function startAnimation(callback) {\\n var runners = [];\\n\\n if (operations.length) {\\n forEach(operations, function (animateFn) {\\n runners.push(animateFn());\\n });\\n }\\n\\n runners.length ? $$AnimateRunner.all(runners, callback) : callback();\\n return function endFn(reject) {\\n forEach(runners, function (runner) {\\n reject ? runner.cancel() : runner.end();\\n });\\n };\\n };\\n }\\n };\\n\\n function lookupAnimations(classes) {\\n classes = isArray(classes) ? classes : classes.split(' ');\\n var matches = [],\\n flagMap = {};\\n\\n for (var i = 0; i < classes.length; i++) {\\n var klass = classes[i],\\n animationFactory = $animateProvider.$$registeredAnimations[klass];\\n\\n if (animationFactory && !flagMap[klass]) {\\n matches.push($injector.get(animationFactory));\\n flagMap[klass] = true;\\n }\\n }\\n\\n return matches;\\n }\\n }];\\n }];\\n var $$AnimateJsDriverProvider = ['$$animationProvider', function ($$animationProvider) {\\n $$animationProvider.drivers.push('$$animateJsDriver');\\n this.$get = ['$$animateJs', '$$AnimateRunner', function ($$animateJs, $$AnimateRunner) {\\n return function initDriverFn(animationDetails) {\\n if (animationDetails.from && animationDetails.to) {\\n var fromAnimation = prepareAnimation(animationDetails.from);\\n var toAnimation = prepareAnimation(animationDetails.to);\\n if (!fromAnimation && !toAnimation) return;\\n return {\\n start: function () {\\n var animationRunners = [];\\n\\n if (fromAnimation) {\\n animationRunners.push(fromAnimation.start());\\n }\\n\\n if (toAnimation) {\\n animationRunners.push(toAnimation.start());\\n }\\n\\n $$AnimateRunner.all(animationRunners, done);\\n var runner = new $$AnimateRunner({\\n end: endFnFactory(),\\n cancel: endFnFactory()\\n });\\n return runner;\\n\\n function endFnFactory() {\\n return function () {\\n forEach(animationRunners, function (runner) {\\n // at this point we cannot cancel animations for groups just yet. 1.5+\\n runner.end();\\n });\\n };\\n }\\n\\n function done(status) {\\n runner.complete(status);\\n }\\n }\\n };\\n } else {\\n return prepareAnimation(animationDetails);\\n }\\n };\\n\\n function prepareAnimation(animationDetails) {\\n // TODO(matsko): make sure to check for grouped animations and delegate down to normal animations\\n var element = animationDetails.element;\\n var event = animationDetails.event;\\n var options = animationDetails.options;\\n var classes = animationDetails.classes;\\n return $$animateJs(element, event, classes, options);\\n }\\n }];\\n }];\\n var NG_ANIMATE_ATTR_NAME = 'data-ng-animate';\\n var NG_ANIMATE_PIN_DATA = '$ngAnimatePin';\\n var $$AnimateQueueProvider = ['$animateProvider', function ($animateProvider) {\\n var PRE_DIGEST_STATE = 1;\\n var RUNNING_STATE = 2;\\n var ONE_SPACE = ' ';\\n var rules = this.rules = {\\n skip: [],\\n cancel: [],\\n join: []\\n };\\n\\n function makeTruthyCssClassMap(classString) {\\n if (!classString) {\\n return null;\\n }\\n\\n var keys = classString.split(ONE_SPACE);\\n var map = Object.create(null);\\n forEach(keys, function (key) {\\n map[key] = true;\\n });\\n return map;\\n }\\n\\n function hasMatchingClasses(newClassString, currentClassString) {\\n if (newClassString && currentClassString) {\\n var currentClassMap = makeTruthyCssClassMap(currentClassString);\\n return newClassString.split(ONE_SPACE).some(function (className) {\\n return currentClassMap[className];\\n });\\n }\\n }\\n\\n function isAllowed(ruleType, element, currentAnimation, previousAnimation) {\\n return rules[ruleType].some(function (fn) {\\n return fn(element, currentAnimation, previousAnimation);\\n });\\n }\\n\\n function hasAnimationClasses(animation, and) {\\n var a = (animation.addClass || '').length > 0;\\n var b = (animation.removeClass || '').length > 0;\\n return and ? a && b : a || b;\\n }\\n\\n rules.join.push(function (element, newAnimation, currentAnimation) {\\n // if the new animation is class-based then we can just tack that on\\n return !newAnimation.structural && hasAnimationClasses(newAnimation);\\n });\\n rules.skip.push(function (element, newAnimation, currentAnimation) {\\n // there is no need to animate anything if no classes are being added and\\n // there is no structural animation that will be triggered\\n return !newAnimation.structural && !hasAnimationClasses(newAnimation);\\n });\\n rules.skip.push(function (element, newAnimation, currentAnimation) {\\n // why should we trigger a new structural animation if the element will\\n // be removed from the DOM anyway?\\n return currentAnimation.event == 'leave' && newAnimation.structural;\\n });\\n rules.skip.push(function (element, newAnimation, currentAnimation) {\\n // if there is an ongoing current animation then don't even bother running the class-based animation\\n return currentAnimation.structural && currentAnimation.state === RUNNING_STATE && !newAnimation.structural;\\n });\\n rules.cancel.push(function (element, newAnimation, currentAnimation) {\\n // there can never be two structural animations running at the same time\\n return currentAnimation.structural && newAnimation.structural;\\n });\\n rules.cancel.push(function (element, newAnimation, currentAnimation) {\\n // if the previous animation is already running, but the new animation will\\n // be triggered, but the new animation is structural\\n return currentAnimation.state === RUNNING_STATE && newAnimation.structural;\\n });\\n rules.cancel.push(function (element, newAnimation, currentAnimation) {\\n var nA = newAnimation.addClass;\\n var nR = newAnimation.removeClass;\\n var cA = currentAnimation.addClass;\\n var cR = currentAnimation.removeClass; // early detection to save the global CPU shortage :)\\n\\n if (isUndefined(nA) && isUndefined(nR) || isUndefined(cA) && isUndefined(cR)) {\\n return false;\\n }\\n\\n return hasMatchingClasses(nA, cR) || hasMatchingClasses(nR, cA);\\n });\\n this.$get = ['$$rAF', '$rootScope', '$rootElement', '$document', '$$HashMap', '$$animation', '$$AnimateRunner', '$templateRequest', '$$jqLite', '$$forceReflow', function ($$rAF, $rootScope, $rootElement, $document, $$HashMap, $$animation, $$AnimateRunner, $templateRequest, $$jqLite, $$forceReflow) {\\n var activeAnimationsLookup = new $$HashMap();\\n var disabledElementsLookup = new $$HashMap();\\n var animationsEnabled = null;\\n\\n function postDigestTaskFactory() {\\n var postDigestCalled = false;\\n return function (fn) {\\n // we only issue a call to postDigest before\\n // it has first passed. This prevents any callbacks\\n // from not firing once the animation has completed\\n // since it will be out of the digest cycle.\\n if (postDigestCalled) {\\n fn();\\n } else {\\n $rootScope.$$postDigest(function () {\\n postDigestCalled = true;\\n fn();\\n });\\n }\\n };\\n } // Wait until all directive and route-related templates are downloaded and\\n // compiled. The $templateRequest.totalPendingRequests variable keeps track of\\n // all of the remote templates being currently downloaded. If there are no\\n // templates currently downloading then the watcher will still fire anyway.\\n\\n\\n var deregisterWatch = $rootScope.$watch(function () {\\n return $templateRequest.totalPendingRequests === 0;\\n }, function (isEmpty) {\\n if (!isEmpty) return;\\n deregisterWatch(); // Now that all templates have been downloaded, $animate will wait until\\n // the post digest queue is empty before enabling animations. By having two\\n // calls to $postDigest calls we can ensure that the flag is enabled at the\\n // very end of the post digest queue. Since all of the animations in $animate\\n // use $postDigest, it's important that the code below executes at the end.\\n // This basically means that the page is fully downloaded and compiled before\\n // any animations are triggered.\\n\\n $rootScope.$$postDigest(function () {\\n $rootScope.$$postDigest(function () {\\n // we check for null directly in the event that the application already called\\n // .enabled() with whatever arguments that it provided it with\\n if (animationsEnabled === null) {\\n animationsEnabled = true;\\n }\\n });\\n });\\n });\\n var callbackRegistry = {}; // remember that the classNameFilter is set during the provider/config\\n // stage therefore we can optimize here and setup a helper function\\n\\n var classNameFilter = $animateProvider.classNameFilter();\\n var isAnimatableClassName = !classNameFilter ? function () {\\n return true;\\n } : function (className) {\\n return classNameFilter.test(className);\\n };\\n var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\\n\\n function normalizeAnimationDetails(element, animation) {\\n return mergeAnimationDetails(element, animation, {});\\n } // IE9-11 has no method \\\"contains\\\" in SVG element and in Node.prototype. Bug #10259.\\n\\n\\n var contains = Node.prototype.contains || function (arg) {\\n // jshint bitwise: false\\n return this === arg || !!(this.compareDocumentPosition(arg) & 16); // jshint bitwise: true\\n };\\n\\n function findCallbacks(parent, element, event) {\\n var targetNode = getDomNode(element);\\n var targetParentNode = getDomNode(parent);\\n var matches = [];\\n var entries = callbackRegistry[event];\\n\\n if (entries) {\\n forEach(entries, function (entry) {\\n if (contains.call(entry.node, targetNode)) {\\n matches.push(entry.callback);\\n } else if (event === 'leave' && contains.call(entry.node, targetParentNode)) {\\n matches.push(entry.callback);\\n }\\n });\\n }\\n\\n return matches;\\n }\\n\\n return {\\n on: function (event, container, callback) {\\n var node = extractElementNode(container);\\n callbackRegistry[event] = callbackRegistry[event] || [];\\n callbackRegistry[event].push({\\n node: node,\\n callback: callback\\n });\\n },\\n off: function (event, container, callback) {\\n var entries = callbackRegistry[event];\\n if (!entries) return;\\n callbackRegistry[event] = arguments.length === 1 ? null : filterFromRegistry(entries, container, callback);\\n\\n function filterFromRegistry(list, matchContainer, matchCallback) {\\n var containerNode = extractElementNode(matchContainer);\\n return list.filter(function (entry) {\\n var isMatch = entry.node === containerNode && (!matchCallback || entry.callback === matchCallback);\\n return !isMatch;\\n });\\n }\\n },\\n pin: function (element, parentElement) {\\n assertArg(isElement(element), 'element', 'not an element');\\n assertArg(isElement(parentElement), 'parentElement', 'not an element');\\n element.data(NG_ANIMATE_PIN_DATA, parentElement);\\n },\\n push: function (element, event, options, domOperation) {\\n options = options || {};\\n options.domOperation = domOperation;\\n return queueAnimation(element, event, options);\\n },\\n // this method has four signatures:\\n // () - global getter\\n // (bool) - global setter\\n // (element) - element getter\\n // (element, bool) - element setter\\n enabled: function (element, bool) {\\n var argCount = arguments.length;\\n\\n if (argCount === 0) {\\n // () - Global getter\\n bool = !!animationsEnabled;\\n } else {\\n var hasElement = isElement(element);\\n\\n if (!hasElement) {\\n // (bool) - Global setter\\n bool = animationsEnabled = !!element;\\n } else {\\n var node = getDomNode(element);\\n var recordExists = disabledElementsLookup.get(node);\\n\\n if (argCount === 1) {\\n // (element) - Element getter\\n bool = !recordExists;\\n } else {\\n // (element, bool) - Element setter\\n disabledElementsLookup.put(node, !bool);\\n }\\n }\\n }\\n\\n return bool;\\n }\\n };\\n\\n function queueAnimation(element, event, initialOptions) {\\n // we always make a copy of the options since\\n // there should never be any side effects on\\n // the input data when running `$animateCss`.\\n var options = copy(initialOptions);\\n var node, parent;\\n element = stripCommentsFromElement(element);\\n\\n if (element) {\\n node = getDomNode(element);\\n parent = element.parent();\\n }\\n\\n options = prepareAnimationOptions(options); // we create a fake runner with a working promise.\\n // These methods will become available after the digest has passed\\n\\n var runner = new $$AnimateRunner(); // this is used to trigger callbacks in postDigest mode\\n\\n var runInNextPostDigestOrNow = postDigestTaskFactory();\\n\\n if (isArray(options.addClass)) {\\n options.addClass = options.addClass.join(' ');\\n }\\n\\n if (options.addClass && !isString(options.addClass)) {\\n options.addClass = null;\\n }\\n\\n if (isArray(options.removeClass)) {\\n options.removeClass = options.removeClass.join(' ');\\n }\\n\\n if (options.removeClass && !isString(options.removeClass)) {\\n options.removeClass = null;\\n }\\n\\n if (options.from && !isObject(options.from)) {\\n options.from = null;\\n }\\n\\n if (options.to && !isObject(options.to)) {\\n options.to = null;\\n } // there are situations where a directive issues an animation for\\n // a jqLite wrapper that contains only comment nodes... If this\\n // happens then there is no way we can perform an animation\\n\\n\\n if (!node) {\\n close();\\n return runner;\\n }\\n\\n var className = [node.className, options.addClass, options.removeClass].join(' ');\\n\\n if (!isAnimatableClassName(className)) {\\n close();\\n return runner;\\n }\\n\\n var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0; // this is a hard disable of all animations for the application or on\\n // the element itself, therefore there is no need to continue further\\n // past this point if not enabled\\n // Animations are also disabled if the document is currently hidden (page is not visible\\n // to the user), because browsers slow down or do not flush calls to requestAnimationFrame\\n\\n var skipAnimations = !animationsEnabled || $document[0].hidden || disabledElementsLookup.get(node);\\n var existingAnimation = !skipAnimations && activeAnimationsLookup.get(node) || {};\\n var hasExistingAnimation = !!existingAnimation.state; // there is no point in traversing the same collection of parent ancestors if a followup\\n // animation will be run on the same element that already did all that checking work\\n\\n if (!skipAnimations && (!hasExistingAnimation || existingAnimation.state != PRE_DIGEST_STATE)) {\\n skipAnimations = !areAnimationsAllowed(element, parent, event);\\n }\\n\\n if (skipAnimations) {\\n close();\\n return runner;\\n }\\n\\n if (isStructural) {\\n closeChildAnimations(element);\\n }\\n\\n var newAnimation = {\\n structural: isStructural,\\n element: element,\\n event: event,\\n addClass: options.addClass,\\n removeClass: options.removeClass,\\n close: close,\\n options: options,\\n runner: runner\\n };\\n\\n if (hasExistingAnimation) {\\n var skipAnimationFlag = isAllowed('skip', element, newAnimation, existingAnimation);\\n\\n if (skipAnimationFlag) {\\n if (existingAnimation.state === RUNNING_STATE) {\\n close();\\n return runner;\\n } else {\\n mergeAnimationDetails(element, existingAnimation, newAnimation);\\n return existingAnimation.runner;\\n }\\n }\\n\\n var cancelAnimationFlag = isAllowed('cancel', element, newAnimation, existingAnimation);\\n\\n if (cancelAnimationFlag) {\\n if (existingAnimation.state === RUNNING_STATE) {\\n // this will end the animation right away and it is safe\\n // to do so since the animation is already running and the\\n // runner callback code will run in async\\n existingAnimation.runner.end();\\n } else if (existingAnimation.structural) {\\n // this means that the animation is queued into a digest, but\\n // hasn't started yet. Therefore it is safe to run the close\\n // method which will call the runner methods in async.\\n existingAnimation.close();\\n } else {\\n // this will merge the new animation options into existing animation options\\n mergeAnimationDetails(element, existingAnimation, newAnimation);\\n return existingAnimation.runner;\\n }\\n } else {\\n // a joined animation means that this animation will take over the existing one\\n // so an example would involve a leave animation taking over an enter. Then when\\n // the postDigest kicks in the enter will be ignored.\\n var joinAnimationFlag = isAllowed('join', element, newAnimation, existingAnimation);\\n\\n if (joinAnimationFlag) {\\n if (existingAnimation.state === RUNNING_STATE) {\\n normalizeAnimationDetails(element, newAnimation);\\n } else {\\n applyGeneratedPreparationClasses(element, isStructural ? event : null, options);\\n event = newAnimation.event = existingAnimation.event;\\n options = mergeAnimationDetails(element, existingAnimation, newAnimation); //we return the same runner since only the option values of this animation will\\n //be fed into the `existingAnimation`.\\n\\n return existingAnimation.runner;\\n }\\n }\\n }\\n } else {\\n // normalization in this case means that it removes redundant CSS classes that\\n // already exist (addClass) or do not exist (removeClass) on the element\\n normalizeAnimationDetails(element, newAnimation);\\n } // when the options are merged and cleaned up we may end up not having to do\\n // an animation at all, therefore we should check this before issuing a post\\n // digest callback. Structural animations will always run no matter what.\\n\\n\\n var isValidAnimation = newAnimation.structural;\\n\\n if (!isValidAnimation) {\\n // animate (from/to) can be quickly checked first, otherwise we check if any classes are present\\n isValidAnimation = newAnimation.event === 'animate' && Object.keys(newAnimation.options.to || {}).length > 0 || hasAnimationClasses(newAnimation);\\n }\\n\\n if (!isValidAnimation) {\\n close();\\n clearElementAnimationState(element);\\n return runner;\\n } // the counter keeps track of cancelled animations\\n\\n\\n var counter = (existingAnimation.counter || 0) + 1;\\n newAnimation.counter = counter;\\n markElementAnimationState(element, PRE_DIGEST_STATE, newAnimation);\\n $rootScope.$$postDigest(function () {\\n var animationDetails = activeAnimationsLookup.get(node);\\n var animationCancelled = !animationDetails;\\n animationDetails = animationDetails || {}; // if addClass/removeClass is called before something like enter then the\\n // registered parent element may not be present. The code below will ensure\\n // that a final value for parent element is obtained\\n\\n var parentElement = element.parent() || []; // animate/structural/class-based animations all have requirements. Otherwise there\\n // is no point in performing an animation. The parent node must also be set.\\n\\n var isValidAnimation = parentElement.length > 0 && (animationDetails.event === 'animate' || animationDetails.structural || hasAnimationClasses(animationDetails)); // this means that the previous animation was cancelled\\n // even if the follow-up animation is the same event\\n\\n if (animationCancelled || animationDetails.counter !== counter || !isValidAnimation) {\\n // if another animation did not take over then we need\\n // to make sure that the domOperation and options are\\n // handled accordingly\\n if (animationCancelled) {\\n applyAnimationClasses(element, options);\\n applyAnimationStyles(element, options);\\n } // if the event changed from something like enter to leave then we do\\n // it, otherwise if it's the same then the end result will be the same too\\n\\n\\n if (animationCancelled || isStructural && animationDetails.event !== event) {\\n options.domOperation();\\n runner.end();\\n } // in the event that the element animation was not cancelled or a follow-up animation\\n // isn't allowed to animate from here then we need to clear the state of the element\\n // so that any future animations won't read the expired animation data.\\n\\n\\n if (!isValidAnimation) {\\n clearElementAnimationState(element);\\n }\\n\\n return;\\n } // this combined multiple class to addClass / removeClass into a setClass event\\n // so long as a structural event did not take over the animation\\n\\n\\n event = !animationDetails.structural && hasAnimationClasses(animationDetails, true) ? 'setClass' : animationDetails.event;\\n markElementAnimationState(element, RUNNING_STATE);\\n var realRunner = $$animation(element, event, animationDetails.options);\\n realRunner.done(function (status) {\\n close(!status);\\n var animationDetails = activeAnimationsLookup.get(node);\\n\\n if (animationDetails && animationDetails.counter === counter) {\\n clearElementAnimationState(getDomNode(element));\\n }\\n\\n notifyProgress(runner, event, 'close', {});\\n }); // this will update the runner's flow-control events based on\\n // the `realRunner` object.\\n\\n runner.setHost(realRunner);\\n notifyProgress(runner, event, 'start', {});\\n });\\n return runner;\\n\\n function notifyProgress(runner, event, phase, data) {\\n runInNextPostDigestOrNow(function () {\\n var callbacks = findCallbacks(parent, element, event);\\n\\n if (callbacks.length) {\\n // do not optimize this call here to RAF because\\n // we don't know how heavy the callback code here will\\n // be and if this code is buffered then this can\\n // lead to a performance regression.\\n $$rAF(function () {\\n forEach(callbacks, function (callback) {\\n callback(element, phase, data);\\n });\\n });\\n }\\n });\\n runner.progress(event, phase, data);\\n }\\n\\n function close(reject) {\\n // jshint ignore:line\\n clearGeneratedClasses(element, options);\\n applyAnimationClasses(element, options);\\n applyAnimationStyles(element, options);\\n options.domOperation();\\n runner.complete(!reject);\\n }\\n }\\n\\n function closeChildAnimations(element) {\\n var node = getDomNode(element);\\n var children = node.querySelectorAll('[' + NG_ANIMATE_ATTR_NAME + ']');\\n forEach(children, function (child) {\\n var state = parseInt(child.getAttribute(NG_ANIMATE_ATTR_NAME));\\n var animationDetails = activeAnimationsLookup.get(child);\\n\\n if (animationDetails) {\\n switch (state) {\\n case RUNNING_STATE:\\n animationDetails.runner.end();\\n\\n /* falls through */\\n\\n case PRE_DIGEST_STATE:\\n activeAnimationsLookup.remove(child);\\n break;\\n }\\n }\\n });\\n }\\n\\n function clearElementAnimationState(element) {\\n var node = getDomNode(element);\\n node.removeAttribute(NG_ANIMATE_ATTR_NAME);\\n activeAnimationsLookup.remove(node);\\n }\\n\\n function isMatchingElement(nodeOrElmA, nodeOrElmB) {\\n return getDomNode(nodeOrElmA) === getDomNode(nodeOrElmB);\\n }\\n /**\\r\\n * This fn returns false if any of the following is true:\\r\\n * a) animations on any parent element are disabled, and animations on the element aren't explicitly allowed\\r\\n * b) a parent element has an ongoing structural animation, and animateChildren is false\\r\\n * c) the element is not a child of the body\\r\\n * d) the element is not a child of the $rootElement\\r\\n */\\n\\n\\n function areAnimationsAllowed(element, parentElement, event) {\\n var bodyElement = jqLite($document[0].body);\\n var bodyElementDetected = isMatchingElement(element, bodyElement) || element[0].nodeName === 'HTML';\\n var rootElementDetected = isMatchingElement(element, $rootElement);\\n var parentAnimationDetected = false;\\n var animateChildren;\\n var elementDisabled = disabledElementsLookup.get(getDomNode(element));\\n var parentHost = element.data(NG_ANIMATE_PIN_DATA);\\n\\n if (parentHost) {\\n parentElement = parentHost;\\n }\\n\\n while (parentElement && parentElement.length) {\\n if (!rootElementDetected) {\\n // angular doesn't want to attempt to animate elements outside of the application\\n // therefore we need to ensure that the rootElement is an ancestor of the current element\\n rootElementDetected = isMatchingElement(parentElement, $rootElement);\\n }\\n\\n var parentNode = parentElement[0];\\n\\n if (parentNode.nodeType !== ELEMENT_NODE) {\\n // no point in inspecting the #document element\\n break;\\n }\\n\\n var details = activeAnimationsLookup.get(parentNode) || {}; // either an enter, leave or move animation will commence\\n // therefore we can't allow any animations to take place\\n // but if a parent animation is class-based then that's ok\\n\\n if (!parentAnimationDetected) {\\n var parentElementDisabled = disabledElementsLookup.get(parentNode);\\n\\n if (parentElementDisabled === true && elementDisabled !== false) {\\n // disable animations if the user hasn't explicitly enabled animations on the\\n // current element\\n elementDisabled = true; // element is disabled via parent element, no need to check anything else\\n\\n break;\\n } else if (parentElementDisabled === false) {\\n elementDisabled = false;\\n }\\n\\n parentAnimationDetected = details.structural;\\n }\\n\\n if (isUndefined(animateChildren) || animateChildren === true) {\\n var value = parentElement.data(NG_ANIMATE_CHILDREN_DATA);\\n\\n if (isDefined(value)) {\\n animateChildren = value;\\n }\\n } // there is no need to continue traversing at this point\\n\\n\\n if (parentAnimationDetected && animateChildren === false) break;\\n\\n if (!bodyElementDetected) {\\n // we also need to ensure that the element is or will be a part of the body element\\n // otherwise it is pointless to even issue an animation to be rendered\\n bodyElementDetected = isMatchingElement(parentElement, bodyElement);\\n }\\n\\n if (bodyElementDetected && rootElementDetected) {\\n // If both body and root have been found, any other checks are pointless,\\n // as no animation data should live outside the application\\n break;\\n }\\n\\n if (!rootElementDetected) {\\n // If no rootElement is detected, check if the parentElement is pinned to another element\\n parentHost = parentElement.data(NG_ANIMATE_PIN_DATA);\\n\\n if (parentHost) {\\n // The pin target element becomes the next parent element\\n parentElement = parentHost;\\n continue;\\n }\\n }\\n\\n parentElement = parentElement.parent();\\n }\\n\\n var allowAnimation = (!parentAnimationDetected || animateChildren) && elementDisabled !== true;\\n return allowAnimation && rootElementDetected && bodyElementDetected;\\n }\\n\\n function markElementAnimationState(element, state, details) {\\n details = details || {};\\n details.state = state;\\n var node = getDomNode(element);\\n node.setAttribute(NG_ANIMATE_ATTR_NAME, state);\\n var oldValue = activeAnimationsLookup.get(node);\\n var newValue = oldValue ? extend(oldValue, details) : details;\\n activeAnimationsLookup.put(node, newValue);\\n }\\n }];\\n }];\\n var $$AnimationProvider = ['$animateProvider', function ($animateProvider) {\\n var NG_ANIMATE_REF_ATTR = 'ng-animate-ref';\\n var drivers = this.drivers = [];\\n var RUNNER_STORAGE_KEY = '$$animationRunner';\\n\\n function setRunner(element, runner) {\\n element.data(RUNNER_STORAGE_KEY, runner);\\n }\\n\\n function removeRunner(element) {\\n element.removeData(RUNNER_STORAGE_KEY);\\n }\\n\\n function getRunner(element) {\\n return element.data(RUNNER_STORAGE_KEY);\\n }\\n\\n this.$get = ['$$jqLite', '$rootScope', '$injector', '$$AnimateRunner', '$$HashMap', '$$rAFScheduler', function ($$jqLite, $rootScope, $injector, $$AnimateRunner, $$HashMap, $$rAFScheduler) {\\n var animationQueue = [];\\n var applyAnimationClasses = applyAnimationClassesFactory($$jqLite);\\n\\n function sortAnimations(animations) {\\n var tree = {\\n children: []\\n };\\n var i,\\n lookup = new $$HashMap(); // this is done first beforehand so that the hashmap\\n // is filled with a list of the elements that will be animated\\n\\n for (i = 0; i < animations.length; i++) {\\n var animation = animations[i];\\n lookup.put(animation.domNode, animations[i] = {\\n domNode: animation.domNode,\\n fn: animation.fn,\\n children: []\\n });\\n }\\n\\n for (i = 0; i < animations.length; i++) {\\n processNode(animations[i]);\\n }\\n\\n return flatten(tree);\\n\\n function processNode(entry) {\\n if (entry.processed) return entry;\\n entry.processed = true;\\n var elementNode = entry.domNode;\\n var parentNode = elementNode.parentNode;\\n lookup.put(elementNode, entry);\\n var parentEntry;\\n\\n while (parentNode) {\\n parentEntry = lookup.get(parentNode);\\n\\n if (parentEntry) {\\n if (!parentEntry.processed) {\\n parentEntry = processNode(parentEntry);\\n }\\n\\n break;\\n }\\n\\n parentNode = parentNode.parentNode;\\n }\\n\\n (parentEntry || tree).children.push(entry);\\n return entry;\\n }\\n\\n function flatten(tree) {\\n var result = [];\\n var queue = [];\\n var i;\\n\\n for (i = 0; i < tree.children.length; i++) {\\n queue.push(tree.children[i]);\\n }\\n\\n var remainingLevelEntries = queue.length;\\n var nextLevelEntries = 0;\\n var row = [];\\n\\n for (i = 0; i < queue.length; i++) {\\n var entry = queue[i];\\n\\n if (remainingLevelEntries <= 0) {\\n remainingLevelEntries = nextLevelEntries;\\n nextLevelEntries = 0;\\n result.push(row);\\n row = [];\\n }\\n\\n row.push(entry.fn);\\n entry.children.forEach(function (childEntry) {\\n nextLevelEntries++;\\n queue.push(childEntry);\\n });\\n remainingLevelEntries--;\\n }\\n\\n if (row.length) {\\n result.push(row);\\n }\\n\\n return result;\\n }\\n } // TODO(matsko): document the signature in a better way\\n\\n\\n return function (element, event, options) {\\n options = prepareAnimationOptions(options);\\n var isStructural = ['enter', 'move', 'leave'].indexOf(event) >= 0; // there is no animation at the current moment, however\\n // these runner methods will get later updated with the\\n // methods leading into the driver's end/cancel methods\\n // for now they just stop the animation from starting\\n\\n var runner = new $$AnimateRunner({\\n end: function () {\\n close();\\n },\\n cancel: function () {\\n close(true);\\n }\\n });\\n\\n if (!drivers.length) {\\n close();\\n return runner;\\n }\\n\\n setRunner(element, runner);\\n var classes = mergeClasses(element.attr('class'), mergeClasses(options.addClass, options.removeClass));\\n var tempClasses = options.tempClasses;\\n\\n if (tempClasses) {\\n classes += ' ' + tempClasses;\\n options.tempClasses = null;\\n }\\n\\n var prepareClassName;\\n\\n if (isStructural) {\\n prepareClassName = 'ng-' + event + PREPARE_CLASS_SUFFIX;\\n $$jqLite.addClass(element, prepareClassName);\\n }\\n\\n animationQueue.push({\\n // this data is used by the postDigest code and passed into\\n // the driver step function\\n element: element,\\n classes: classes,\\n event: event,\\n structural: isStructural,\\n options: options,\\n beforeStart: beforeStart,\\n close: close\\n });\\n element.on('$destroy', handleDestroyedElement); // we only want there to be one function called within the post digest\\n // block. This way we can group animations for all the animations that\\n // were apart of the same postDigest flush call.\\n\\n if (animationQueue.length > 1) return runner;\\n $rootScope.$$postDigest(function () {\\n var animations = [];\\n forEach(animationQueue, function (entry) {\\n // the element was destroyed early on which removed the runner\\n // form its storage. This means we can't animate this element\\n // at all and it already has been closed due to destruction.\\n if (getRunner(entry.element)) {\\n animations.push(entry);\\n } else {\\n entry.close();\\n }\\n }); // now any future animations will be in another postDigest\\n\\n animationQueue.length = 0;\\n var groupedAnimations = groupAnimations(animations);\\n var toBeSortedAnimations = [];\\n forEach(groupedAnimations, function (animationEntry) {\\n toBeSortedAnimations.push({\\n domNode: getDomNode(animationEntry.from ? animationEntry.from.element : animationEntry.element),\\n fn: function triggerAnimationStart() {\\n // it's important that we apply the `ng-animate` CSS class and the\\n // temporary classes before we do any driver invoking since these\\n // CSS classes may be required for proper CSS detection.\\n animationEntry.beforeStart();\\n var startAnimationFn,\\n closeFn = animationEntry.close; // in the event that the element was removed before the digest runs or\\n // during the RAF sequencing then we should not trigger the animation.\\n\\n var targetElement = animationEntry.anchors ? animationEntry.from.element || animationEntry.to.element : animationEntry.element;\\n\\n if (getRunner(targetElement)) {\\n var operation = invokeFirstDriver(animationEntry);\\n\\n if (operation) {\\n startAnimationFn = operation.start;\\n }\\n }\\n\\n if (!startAnimationFn) {\\n closeFn();\\n } else {\\n var animationRunner = startAnimationFn();\\n animationRunner.done(function (status) {\\n closeFn(!status);\\n });\\n updateAnimationRunners(animationEntry, animationRunner);\\n }\\n }\\n });\\n }); // we need to sort each of the animations in order of parent to child\\n // relationships. This ensures that the child classes are applied at the\\n // right time.\\n\\n $$rAFScheduler(sortAnimations(toBeSortedAnimations));\\n });\\n return runner; // TODO(matsko): change to reference nodes\\n\\n function getAnchorNodes(node) {\\n var SELECTOR = '[' + NG_ANIMATE_REF_ATTR + ']';\\n var items = node.hasAttribute(NG_ANIMATE_REF_ATTR) ? [node] : node.querySelectorAll(SELECTOR);\\n var anchors = [];\\n forEach(items, function (node) {\\n var attr = node.getAttribute(NG_ANIMATE_REF_ATTR);\\n\\n if (attr && attr.length) {\\n anchors.push(node);\\n }\\n });\\n return anchors;\\n }\\n\\n function groupAnimations(animations) {\\n var preparedAnimations = [];\\n var refLookup = {};\\n forEach(animations, function (animation, index) {\\n var element = animation.element;\\n var node = getDomNode(element);\\n var event = animation.event;\\n var enterOrMove = ['enter', 'move'].indexOf(event) >= 0;\\n var anchorNodes = animation.structural ? getAnchorNodes(node) : [];\\n\\n if (anchorNodes.length) {\\n var direction = enterOrMove ? 'to' : 'from';\\n forEach(anchorNodes, function (anchor) {\\n var key = anchor.getAttribute(NG_ANIMATE_REF_ATTR);\\n refLookup[key] = refLookup[key] || {};\\n refLookup[key][direction] = {\\n animationID: index,\\n element: jqLite(anchor)\\n };\\n });\\n } else {\\n preparedAnimations.push(animation);\\n }\\n });\\n var usedIndicesLookup = {};\\n var anchorGroups = {};\\n forEach(refLookup, function (operations, key) {\\n var from = operations.from;\\n var to = operations.to;\\n\\n if (!from || !to) {\\n // only one of these is set therefore we can't have an\\n // anchor animation since all three pieces are required\\n var index = from ? from.animationID : to.animationID;\\n var indexKey = index.toString();\\n\\n if (!usedIndicesLookup[indexKey]) {\\n usedIndicesLookup[indexKey] = true;\\n preparedAnimations.push(animations[index]);\\n }\\n\\n return;\\n }\\n\\n var fromAnimation = animations[from.animationID];\\n var toAnimation = animations[to.animationID];\\n var lookupKey = from.animationID.toString();\\n\\n if (!anchorGroups[lookupKey]) {\\n var group = anchorGroups[lookupKey] = {\\n structural: true,\\n beforeStart: function () {\\n fromAnimation.beforeStart();\\n toAnimation.beforeStart();\\n },\\n close: function () {\\n fromAnimation.close();\\n toAnimation.close();\\n },\\n classes: cssClassesIntersection(fromAnimation.classes, toAnimation.classes),\\n from: fromAnimation,\\n to: toAnimation,\\n anchors: [] // TODO(matsko): change to reference nodes\\n\\n }; // the anchor animations require that the from and to elements both have at least\\n // one shared CSS class which effectively marries the two elements together to use\\n // the same animation driver and to properly sequence the anchor animation.\\n\\n if (group.classes.length) {\\n preparedAnimations.push(group);\\n } else {\\n preparedAnimations.push(fromAnimation);\\n preparedAnimations.push(toAnimation);\\n }\\n }\\n\\n anchorGroups[lookupKey].anchors.push({\\n 'out': from.element,\\n 'in': to.element\\n });\\n });\\n return preparedAnimations;\\n }\\n\\n function cssClassesIntersection(a, b) {\\n a = a.split(' ');\\n b = b.split(' ');\\n var matches = [];\\n\\n for (var i = 0; i < a.length; i++) {\\n var aa = a[i];\\n if (aa.substring(0, 3) === 'ng-') continue;\\n\\n for (var j = 0; j < b.length; j++) {\\n if (aa === b[j]) {\\n matches.push(aa);\\n break;\\n }\\n }\\n }\\n\\n return matches.join(' ');\\n }\\n\\n function invokeFirstDriver(animationDetails) {\\n // we loop in reverse order since the more general drivers (like CSS and JS)\\n // may attempt more elements, but custom drivers are more particular\\n for (var i = drivers.length - 1; i >= 0; i--) {\\n var driverName = drivers[i];\\n if (!$injector.has(driverName)) continue; // TODO(matsko): remove this check\\n\\n var factory = $injector.get(driverName);\\n var driver = factory(animationDetails);\\n\\n if (driver) {\\n return driver;\\n }\\n }\\n }\\n\\n function beforeStart() {\\n element.addClass(NG_ANIMATE_CLASSNAME);\\n\\n if (tempClasses) {\\n $$jqLite.addClass(element, tempClasses);\\n }\\n\\n if (prepareClassName) {\\n $$jqLite.removeClass(element, prepareClassName);\\n prepareClassName = null;\\n }\\n }\\n\\n function updateAnimationRunners(animation, newRunner) {\\n if (animation.from && animation.to) {\\n update(animation.from.element);\\n update(animation.to.element);\\n } else {\\n update(animation.element);\\n }\\n\\n function update(element) {\\n getRunner(element).setHost(newRunner);\\n }\\n }\\n\\n function handleDestroyedElement() {\\n var runner = getRunner(element);\\n\\n if (runner && (event !== 'leave' || !options.$$domOperationFired)) {\\n runner.end();\\n }\\n }\\n\\n function close(rejected) {\\n // jshint ignore:line\\n element.off('$destroy', handleDestroyedElement);\\n removeRunner(element);\\n applyAnimationClasses(element, options);\\n applyAnimationStyles(element, options);\\n options.domOperation();\\n\\n if (tempClasses) {\\n $$jqLite.removeClass(element, tempClasses);\\n }\\n\\n element.removeClass(NG_ANIMATE_CLASSNAME);\\n runner.complete(!rejected);\\n }\\n };\\n }];\\n }];\\n /**\\r\\n * @ngdoc directive\\r\\n * @name ngAnimateSwap\\r\\n * @restrict A\\r\\n * @scope\\r\\n *\\r\\n * @description\\r\\n *\\r\\n * ngAnimateSwap is a animation-oriented directive that allows for the container to\\r\\n * be removed and entered in whenever the associated expression changes. A\\r\\n * common usecase for this directive is a rotating banner component which\\r\\n * contains one image being present at a time. When the active image changes\\r\\n * then the old image will perform a `leave` animation and the new element\\r\\n * will be inserted via an `enter` animation.\\r\\n *\\r\\n * @example\\r\\n * \\r\\n * \\r\\n *
\\r\\n *
\\r\\n * {{ number }}\\r\\n *
\\r\\n *
\\r\\n *
\\r\\n * \\r\\n * angular.module('ngAnimateSwapExample', ['ngAnimate'])\\r\\n * .controller('AppCtrl', ['$scope', '$interval', function($scope, $interval) {\\r\\n * $scope.number = 0;\\r\\n * $interval(function() {\\r\\n * $scope.number++;\\r\\n * }, 1000);\\r\\n *\\r\\n * var colors = ['red','blue','green','yellow','orange'];\\r\\n * $scope.colorClass = function(number) {\\r\\n * return colors[number % colors.length];\\r\\n * };\\r\\n * }]);\\r\\n * \\r\\n * \\r\\n * .container {\\r\\n * height:250px;\\r\\n * width:250px;\\r\\n * position:relative;\\r\\n * overflow:hidden;\\r\\n * border:2px solid black;\\r\\n * }\\r\\n * .container .cell {\\r\\n * font-size:150px;\\r\\n * text-align:center;\\r\\n * line-height:250px;\\r\\n * position:absolute;\\r\\n * top:0;\\r\\n * left:0;\\r\\n * right:0;\\r\\n * border-bottom:2px solid black;\\r\\n * }\\r\\n * .swap-animation.ng-enter, .swap-animation.ng-leave {\\r\\n * transition:0.5s linear all;\\r\\n * }\\r\\n * .swap-animation.ng-enter {\\r\\n * top:-250px;\\r\\n * }\\r\\n * .swap-animation.ng-enter-active {\\r\\n * top:0px;\\r\\n * }\\r\\n * .swap-animation.ng-leave {\\r\\n * top:0px;\\r\\n * }\\r\\n * .swap-animation.ng-leave-active {\\r\\n * top:250px;\\r\\n * }\\r\\n * .red { background:red; }\\r\\n * .green { background:green; }\\r\\n * .blue { background:blue; }\\r\\n * .yellow { background:yellow; }\\r\\n * .orange { background:orange; }\\r\\n * \\r\\n *
\\r\\n */\\n\\n var ngAnimateSwapDirective = ['$animate', '$rootScope', function ($animate, $rootScope) {\\n return {\\n restrict: 'A',\\n transclude: 'element',\\n terminal: true,\\n priority: 600,\\n // we use 600 here to ensure that the directive is caught before others\\n link: function (scope, $element, attrs, ctrl, $transclude) {\\n var previousElement, previousScope;\\n scope.$watchCollection(attrs.ngAnimateSwap || attrs['for'], function (value) {\\n if (previousElement) {\\n $animate.leave(previousElement);\\n }\\n\\n if (previousScope) {\\n previousScope.$destroy();\\n previousScope = null;\\n }\\n\\n if (value || value === 0) {\\n previousScope = scope.$new();\\n $transclude(previousScope, function (element) {\\n previousElement = element;\\n $animate.enter(element, null, $element);\\n });\\n }\\n });\\n }\\n };\\n }];\\n /* global angularAnimateModule: true,\\r\\n \\r\\n ngAnimateSwapDirective,\\r\\n $$AnimateAsyncRunFactory,\\r\\n $$rAFSchedulerFactory,\\r\\n $$AnimateChildrenDirective,\\r\\n $$AnimateQueueProvider,\\r\\n $$AnimationProvider,\\r\\n $AnimateCssProvider,\\r\\n $$AnimateCssDriverProvider,\\r\\n $$AnimateJsProvider,\\r\\n $$AnimateJsDriverProvider,\\r\\n */\\n\\n /**\\r\\n * @ngdoc module\\r\\n * @name ngAnimate\\r\\n * @description\\r\\n *\\r\\n * The `ngAnimate` module provides support for CSS-based animations (keyframes and transitions) as well as JavaScript-based animations via\\r\\n * callback hooks. Animations are not enabled by default, however, by including `ngAnimate` the animation hooks are enabled for an Angular app.\\r\\n *\\r\\n *
\\r\\n *\\r\\n * # Usage\\r\\n * Simply put, there are two ways to make use of animations when ngAnimate is used: by using **CSS** and **JavaScript**. The former works purely based\\r\\n * using CSS (by using matching CSS selectors/styles) and the latter triggers animations that are registered via `module.animation()`. For\\r\\n * both CSS and JS animations the sole requirement is to have a matching `CSS class` that exists both in the registered animation and within\\r\\n * the HTML element that the animation will be triggered on.\\r\\n *\\r\\n * ## Directive Support\\r\\n * The following directives are \\\"animation aware\\\":\\r\\n *\\r\\n * | Directive | Supported Animations |\\r\\n * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|\\r\\n * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |\\r\\n * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |\\r\\n * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |\\r\\n * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |\\r\\n * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |\\r\\n * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |\\r\\n * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |\\r\\n * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |\\r\\n * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |\\r\\n * | {@link module:ngMessages#animations ngMessage} | enter and leave |\\r\\n *\\r\\n * (More information can be found by visiting each the documentation associated with each directive.)\\r\\n *\\r\\n * ## CSS-based Animations\\r\\n *\\r\\n * CSS-based animations with ngAnimate are unique since they require no JavaScript code at all. By using a CSS class that we reference between our HTML\\r\\n * and CSS code we can create an animation that will be picked up by Angular when an the underlying directive performs an operation.\\r\\n *\\r\\n * The example below shows how an `enter` animation can be made possible on an element using `ng-if`:\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * Fade me in out\\r\\n *
\\r\\n * \\r\\n * \\r\\n * ```\\r\\n *\\r\\n * Notice the CSS class **fade**? We can now create the CSS transition code that references this class:\\r\\n *\\r\\n * ```css\\r\\n * /* The starting CSS styles for the enter animation */\\r\\n * .fade.ng-enter {\\r\\n * transition:0.5s linear all;\\r\\n * opacity:0;\\r\\n * }\\r\\n *\\r\\n * /* The finishing CSS styles for the enter animation */\\r\\n * .fade.ng-enter.ng-enter-active {\\r\\n * opacity:1;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * The key thing to remember here is that, depending on the animation event (which each of the directives above trigger depending on what's going on) two\\r\\n * generated CSS classes will be applied to the element; in the example above we have `.ng-enter` and `.ng-enter-active`. For CSS transitions, the transition\\r\\n * code **must** be defined within the starting CSS class (in this case `.ng-enter`). The destination class is what the transition will animate towards.\\r\\n *\\r\\n * If for example we wanted to create animations for `leave` and `move` (ngRepeat triggers move) then we can do so using the same CSS naming conventions:\\r\\n *\\r\\n * ```css\\r\\n * /* now the element will fade out before it is removed from the DOM */\\r\\n * .fade.ng-leave {\\r\\n * transition:0.5s linear all;\\r\\n * opacity:1;\\r\\n * }\\r\\n * .fade.ng-leave.ng-leave-active {\\r\\n * opacity:0;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * We can also make use of **CSS Keyframes** by referencing the keyframe animation within the starting CSS class:\\r\\n *\\r\\n * ```css\\r\\n * /* there is no need to define anything inside of the destination\\r\\n * CSS class since the keyframe will take charge of the animation */\\r\\n * .fade.ng-leave {\\r\\n * animation: my_fade_animation 0.5s linear;\\r\\n * -webkit-animation: my_fade_animation 0.5s linear;\\r\\n * }\\r\\n *\\r\\n * @keyframes my_fade_animation {\\r\\n * from { opacity:1; }\\r\\n * to { opacity:0; }\\r\\n * }\\r\\n *\\r\\n * @-webkit-keyframes my_fade_animation {\\r\\n * from { opacity:1; }\\r\\n * to { opacity:0; }\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * Feel free also mix transitions and keyframes together as well as any other CSS classes on the same element.\\r\\n *\\r\\n * ### CSS Class-based Animations\\r\\n *\\r\\n * Class-based animations (animations that are triggered via `ngClass`, `ngShow`, `ngHide` and some other directives) have a slightly different\\r\\n * naming convention. Class-based animations are basic enough that a standard transition or keyframe can be referenced on the class being added\\r\\n * and removed.\\r\\n *\\r\\n * For example if we wanted to do a CSS animation for `ngHide` then we place an animation on the `.ng-hide` CSS class:\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * Show and hide me\\r\\n *
\\r\\n * \\r\\n *\\r\\n * \\r\\n * ```\\r\\n *\\r\\n * All that is going on here with ngShow/ngHide behind the scenes is the `.ng-hide` class is added/removed (when the hidden state is valid). Since\\r\\n * ngShow and ngHide are animation aware then we can match up a transition and ngAnimate handles the rest.\\r\\n *\\r\\n * In addition the addition and removal of the CSS class, ngAnimate also provides two helper methods that we can use to further decorate the animation\\r\\n * with CSS styles.\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * Highlight this box\\r\\n *
\\r\\n * \\r\\n *\\r\\n * \\r\\n * ```\\r\\n *\\r\\n * We can also make use of CSS keyframes by placing them within the CSS classes.\\r\\n *\\r\\n *\\r\\n * ### CSS Staggering Animations\\r\\n * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a\\r\\n * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be\\r\\n * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for\\r\\n * the animation. The style property expected within the stagger class can either be a **transition-delay** or an\\r\\n * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).\\r\\n *\\r\\n * ```css\\r\\n * .my-animation.ng-enter {\\r\\n * /* standard transition code */\\r\\n * transition: 1s linear all;\\r\\n * opacity:0;\\r\\n * }\\r\\n * .my-animation.ng-enter-stagger {\\r\\n * /* this will have a 100ms delay between each successive leave animation */\\r\\n * transition-delay: 0.1s;\\r\\n *\\r\\n * /* As of 1.4.4, this must always be set: it signals ngAnimate\\r\\n * to not accidentally inherit a delay property from another CSS class */\\r\\n * transition-duration: 0s;\\r\\n * }\\r\\n * .my-animation.ng-enter.ng-enter-active {\\r\\n * /* standard transition styles */\\r\\n * opacity:1;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations\\r\\n * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this\\r\\n * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation\\r\\n * will also be reset if one or more animation frames have passed since the multiple calls to `$animate` were fired.\\r\\n *\\r\\n * The following code will issue the **ng-leave-stagger** event on the element provided:\\r\\n *\\r\\n * ```js\\r\\n * var kids = parent.children();\\r\\n *\\r\\n * $animate.leave(kids[0]); //stagger index=0\\r\\n * $animate.leave(kids[1]); //stagger index=1\\r\\n * $animate.leave(kids[2]); //stagger index=2\\r\\n * $animate.leave(kids[3]); //stagger index=3\\r\\n * $animate.leave(kids[4]); //stagger index=4\\r\\n *\\r\\n * window.requestAnimationFrame(function() {\\r\\n * //stagger has reset itself\\r\\n * $animate.leave(kids[5]); //stagger index=0\\r\\n * $animate.leave(kids[6]); //stagger index=1\\r\\n *\\r\\n * $scope.$digest();\\r\\n * });\\r\\n * ```\\r\\n *\\r\\n * Stagger animations are currently only supported within CSS-defined animations.\\r\\n *\\r\\n * ### The `ng-animate` CSS class\\r\\n *\\r\\n * When ngAnimate is animating an element it will apply the `ng-animate` CSS class to the element for the duration of the animation.\\r\\n * This is a temporary CSS class and it will be removed once the animation is over (for both JavaScript and CSS-based animations).\\r\\n *\\r\\n * Therefore, animations can be applied to an element using this temporary class directly via CSS.\\r\\n *\\r\\n * ```css\\r\\n * .zipper.ng-animate {\\r\\n * transition:0.5s linear all;\\r\\n * }\\r\\n * .zipper.ng-enter {\\r\\n * opacity:0;\\r\\n * }\\r\\n * .zipper.ng-enter.ng-enter-active {\\r\\n * opacity:1;\\r\\n * }\\r\\n * .zipper.ng-leave {\\r\\n * opacity:1;\\r\\n * }\\r\\n * .zipper.ng-leave.ng-leave-active {\\r\\n * opacity:0;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * (Note that the `ng-animate` CSS class is reserved and it cannot be applied on an element directly since ngAnimate will always remove\\r\\n * the CSS class once an animation has completed.)\\r\\n *\\r\\n *\\r\\n * ### The `ng-[event]-prepare` class\\r\\n *\\r\\n * This is a special class that can be used to prevent unwanted flickering / flash of content before\\r\\n * the actual animation starts. The class is added as soon as an animation is initialized, but removed\\r\\n * before the actual animation starts (after waiting for a $digest).\\r\\n * It is also only added for *structural* animations (`enter`, `move`, and `leave`).\\r\\n *\\r\\n * In practice, flickering can appear when nesting elements with structural animations such as `ngIf`\\r\\n * into elements that have class-based animations such as `ngClass`.\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n *
\\r\\n *
\\r\\n *
\\r\\n *
\\r\\n * ```\\r\\n *\\r\\n * It is possible that during the `enter` animation, the `.message` div will be briefly visible before it starts animating.\\r\\n * In that case, you can add styles to the CSS that make sure the element stays hidden before the animation starts:\\r\\n *\\r\\n * ```css\\r\\n * .message.ng-enter-prepare {\\r\\n * opacity: 0;\\r\\n * }\\r\\n *\\r\\n * ```\\r\\n *\\r\\n * ## JavaScript-based Animations\\r\\n *\\r\\n * ngAnimate also allows for animations to be consumed by JavaScript code. The approach is similar to CSS-based animations (where there is a shared\\r\\n * CSS class that is referenced in our HTML code) but in addition we need to register the JavaScript animation on the module. By making use of the\\r\\n * `module.animation()` module function we can register the animation.\\r\\n *\\r\\n * Let's see an example of a enter/leave animation using `ngRepeat`:\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * {{ item }}\\r\\n *
\\r\\n * ```\\r\\n *\\r\\n * See the **slide** CSS class? Let's use that class to define an animation that we'll structure in our module code by using `module.animation`:\\r\\n *\\r\\n * ```js\\r\\n * myModule.animation('.slide', [function() {\\r\\n * return {\\r\\n * // make note that other events (like addClass/removeClass)\\r\\n * // have different function input parameters\\r\\n * enter: function(element, doneFn) {\\r\\n * jQuery(element).fadeIn(1000, doneFn);\\r\\n *\\r\\n * // remember to call doneFn so that angular\\r\\n * // knows that the animation has concluded\\r\\n * },\\r\\n *\\r\\n * move: function(element, doneFn) {\\r\\n * jQuery(element).fadeIn(1000, doneFn);\\r\\n * },\\r\\n *\\r\\n * leave: function(element, doneFn) {\\r\\n * jQuery(element).fadeOut(1000, doneFn);\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * The nice thing about JS-based animations is that we can inject other services and make use of advanced animation libraries such as\\r\\n * greensock.js and velocity.js.\\r\\n *\\r\\n * If our animation code class-based (meaning that something like `ngClass`, `ngHide` and `ngShow` triggers it) then we can still define\\r\\n * our animations inside of the same registered animation, however, the function input arguments are a bit different:\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * this box is moody\\r\\n *
\\r\\n * \\r\\n * \\r\\n * \\r\\n * ```\\r\\n *\\r\\n * ```js\\r\\n * myModule.animation('.colorful', [function() {\\r\\n * return {\\r\\n * addClass: function(element, className, doneFn) {\\r\\n * // do some cool animation and call the doneFn\\r\\n * },\\r\\n * removeClass: function(element, className, doneFn) {\\r\\n * // do some cool animation and call the doneFn\\r\\n * },\\r\\n * setClass: function(element, addedClass, removedClass, doneFn) {\\r\\n * // do some cool animation and call the doneFn\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * ## CSS + JS Animations Together\\r\\n *\\r\\n * AngularJS 1.4 and higher has taken steps to make the amalgamation of CSS and JS animations more flexible. However, unlike earlier versions of Angular,\\r\\n * defining CSS and JS animations to work off of the same CSS class will not work anymore. Therefore the example below will only result in **JS animations taking\\r\\n * charge of the animation**:\\r\\n *\\r\\n * ```html\\r\\n *
\\r\\n * Slide in and out\\r\\n *
\\r\\n * ```\\r\\n *\\r\\n * ```js\\r\\n * myModule.animation('.slide', [function() {\\r\\n * return {\\r\\n * enter: function(element, doneFn) {\\r\\n * jQuery(element).slideIn(1000, doneFn);\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * ```css\\r\\n * .slide.ng-enter {\\r\\n * transition:0.5s linear all;\\r\\n * transform:translateY(-100px);\\r\\n * }\\r\\n * .slide.ng-enter.ng-enter-active {\\r\\n * transform:translateY(0);\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * Does this mean that CSS and JS animations cannot be used together? Do JS-based animations always have higher priority? We can make up for the\\r\\n * lack of CSS animations by using the `$animateCss` service to trigger our own tweaked-out, CSS-based animations directly from\\r\\n * our own JS-based animation code:\\r\\n *\\r\\n * ```js\\r\\n * myModule.animation('.slide', ['$animateCss', function($animateCss) {\\r\\n * return {\\r\\n * enter: function(element) {\\r\\n * // this will trigger `.slide.ng-enter` and `.slide.ng-enter-active`.\\r\\n * return $animateCss(element, {\\r\\n * event: 'enter',\\r\\n * structural: true\\r\\n * });\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * The nice thing here is that we can save bandwidth by sticking to our CSS-based animation code and we don't need to rely on a 3rd-party animation framework.\\r\\n *\\r\\n * The `$animateCss` service is very powerful since we can feed in all kinds of extra properties that will be evaluated and fed into a CSS transition or\\r\\n * keyframe animation. For example if we wanted to animate the height of an element while adding and removing classes then we can do so by providing that\\r\\n * data into `$animateCss` directly:\\r\\n *\\r\\n * ```js\\r\\n * myModule.animation('.slide', ['$animateCss', function($animateCss) {\\r\\n * return {\\r\\n * enter: function(element) {\\r\\n * return $animateCss(element, {\\r\\n * event: 'enter',\\r\\n * structural: true,\\r\\n * addClass: 'maroon-setting',\\r\\n * from: { height:0 },\\r\\n * to: { height: 200 }\\r\\n * });\\r\\n * }\\r\\n * }\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * Now we can fill in the rest via our transition CSS code:\\r\\n *\\r\\n * ```css\\r\\n * /* the transition tells ngAnimate to make the animation happen */\\r\\n * .slide.ng-enter { transition:0.5s linear all; }\\r\\n *\\r\\n * /* this extra CSS class will be absorbed into the transition\\r\\n * since the $animateCss code is adding the class */\\r\\n * .maroon-setting { background:red; }\\r\\n * ```\\r\\n *\\r\\n * And `$animateCss` will figure out the rest. Just make sure to have the `done()` callback fire the `doneFn` function to signal when the animation is over.\\r\\n *\\r\\n * To learn more about what's possible be sure to visit the {@link ngAnimate.$animateCss $animateCss service}.\\r\\n *\\r\\n * ## Animation Anchoring (via `ng-animate-ref`)\\r\\n *\\r\\n * ngAnimate in AngularJS 1.4 comes packed with the ability to cross-animate elements between\\r\\n * structural areas of an application (like views) by pairing up elements using an attribute\\r\\n * called `ng-animate-ref`.\\r\\n *\\r\\n * Let's say for example we have two views that are managed by `ng-view` and we want to show\\r\\n * that there is a relationship between two components situated in within these views. By using the\\r\\n * `ng-animate-ref` attribute we can identify that the two components are paired together and we\\r\\n * can then attach an animation, which is triggered when the view changes.\\r\\n *\\r\\n * Say for example we have the following template code:\\r\\n *\\r\\n * ```html\\r\\n * \\r\\n *
\\r\\n *
\\r\\n *\\r\\n * \\r\\n * \\r\\n * \\r\\n * \\r\\n *\\r\\n * \\r\\n * \\r\\n * ```\\r\\n *\\r\\n * Now, when the view changes (once the link is clicked), ngAnimate will examine the\\r\\n * HTML contents to see if there is a match reference between any components in the view\\r\\n * that is leaving and the view that is entering. It will scan both the view which is being\\r\\n * removed (leave) and inserted (enter) to see if there are any paired DOM elements that\\r\\n * contain a matching ref value.\\r\\n *\\r\\n * The two images match since they share the same ref value. ngAnimate will now create a\\r\\n * transport element (which is a clone of the first image element) and it will then attempt\\r\\n * to animate to the position of the second image element in the next view. For the animation to\\r\\n * work a special CSS class called `ng-anchor` will be added to the transported element.\\r\\n *\\r\\n * We can now attach a transition onto the `.banner.ng-anchor` CSS class and then\\r\\n * ngAnimate will handle the entire transition for us as well as the addition and removal of\\r\\n * any changes of CSS classes between the elements:\\r\\n *\\r\\n * ```css\\r\\n * .banner.ng-anchor {\\r\\n * /* this animation will last for 1 second since there are\\r\\n * two phases to the animation (an `in` and an `out` phase) */\\r\\n * transition:0.5s linear all;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * We also **must** include animations for the views that are being entered and removed\\r\\n * (otherwise anchoring wouldn't be possible since the new view would be inserted right away).\\r\\n *\\r\\n * ```css\\r\\n * .view-animation.ng-enter, .view-animation.ng-leave {\\r\\n * transition:0.5s linear all;\\r\\n * position:fixed;\\r\\n * left:0;\\r\\n * top:0;\\r\\n * width:100%;\\r\\n * }\\r\\n * .view-animation.ng-enter {\\r\\n * transform:translateX(100%);\\r\\n * }\\r\\n * .view-animation.ng-leave,\\r\\n * .view-animation.ng-enter.ng-enter-active {\\r\\n * transform:translateX(0%);\\r\\n * }\\r\\n * .view-animation.ng-leave.ng-leave-active {\\r\\n * transform:translateX(-100%);\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * Now we can jump back to the anchor animation. When the animation happens, there are two stages that occur:\\r\\n * an `out` and an `in` stage. The `out` stage happens first and that is when the element is animated away\\r\\n * from its origin. Once that animation is over then the `in` stage occurs which animates the\\r\\n * element to its destination. The reason why there are two animations is to give enough time\\r\\n * for the enter animation on the new element to be ready.\\r\\n *\\r\\n * The example above sets up a transition for both the in and out phases, but we can also target the out or\\r\\n * in phases directly via `ng-anchor-out` and `ng-anchor-in`.\\r\\n *\\r\\n * ```css\\r\\n * .banner.ng-anchor-out {\\r\\n * transition: 0.5s linear all;\\r\\n *\\r\\n * /* the scale will be applied during the out animation,\\r\\n * but will be animated away when the in animation runs */\\r\\n * transform: scale(1.2);\\r\\n * }\\r\\n *\\r\\n * .banner.ng-anchor-in {\\r\\n * transition: 1s linear all;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n *\\r\\n *\\r\\n *\\r\\n * ### Anchoring Demo\\r\\n *\\r\\n \\r\\n \\r\\n Home\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n
\\r\\n \\r\\n angular.module('anchoringExample', ['ngAnimate', 'ngRoute'])\\r\\n .config(['$routeProvider', function($routeProvider) {\\r\\n $routeProvider.when('/', {\\r\\n templateUrl: 'home.html',\\r\\n controller: 'HomeController as home'\\r\\n });\\r\\n $routeProvider.when('/profile/:id', {\\r\\n templateUrl: 'profile.html',\\r\\n controller: 'ProfileController as profile'\\r\\n });\\r\\n }])\\r\\n .run(['$rootScope', function($rootScope) {\\r\\n $rootScope.records = [\\r\\n { id:1, title: \\\"Miss Beulah Roob\\\" },\\r\\n { id:2, title: \\\"Trent Morissette\\\" },\\r\\n { id:3, title: \\\"Miss Ava Pouros\\\" },\\r\\n { id:4, title: \\\"Rod Pouros\\\" },\\r\\n { id:5, title: \\\"Abdul Rice\\\" },\\r\\n { id:6, title: \\\"Laurie Rutherford Sr.\\\" },\\r\\n { id:7, title: \\\"Nakia McLaughlin\\\" },\\r\\n { id:8, title: \\\"Jordon Blanda DVM\\\" },\\r\\n { id:9, title: \\\"Rhoda Hand\\\" },\\r\\n { id:10, title: \\\"Alexandrea Sauer\\\" }\\r\\n ];\\r\\n }])\\r\\n .controller('HomeController', [function() {\\r\\n //empty\\r\\n }])\\r\\n .controller('ProfileController', ['$rootScope', '$routeParams', function($rootScope, $routeParams) {\\r\\n var index = parseInt($routeParams.id, 10);\\r\\n var record = $rootScope.records[index - 1];\\r\\n \\r\\n this.title = record.title;\\r\\n this.id = record.id;\\r\\n }]);\\r\\n \\r\\n \\r\\n

Welcome to the home page

\\r\\n

Please click on an element

\\r\\n \\r\\n {{ record.title }}\\r\\n \\r\\n
\\r\\n \\r\\n
\\r\\n {{ profile.title }}\\r\\n
\\r\\n
\\r\\n \\r\\n .record {\\r\\n display:block;\\r\\n font-size:20px;\\r\\n }\\r\\n .profile {\\r\\n background:black;\\r\\n color:white;\\r\\n font-size:100px;\\r\\n }\\r\\n .view-container {\\r\\n position:relative;\\r\\n }\\r\\n .view-container > .view.ng-animate {\\r\\n position:absolute;\\r\\n top:0;\\r\\n left:0;\\r\\n width:100%;\\r\\n min-height:500px;\\r\\n }\\r\\n .view.ng-enter, .view.ng-leave,\\r\\n .record.ng-anchor {\\r\\n transition:0.5s linear all;\\r\\n }\\r\\n .view.ng-enter {\\r\\n transform:translateX(100%);\\r\\n }\\r\\n .view.ng-enter.ng-enter-active, .view.ng-leave {\\r\\n transform:translateX(0%);\\r\\n }\\r\\n .view.ng-leave.ng-leave-active {\\r\\n transform:translateX(-100%);\\r\\n }\\r\\n .record.ng-anchor-out {\\r\\n background:red;\\r\\n }\\r\\n \\r\\n
\\r\\n *\\r\\n * ### How is the element transported?\\r\\n *\\r\\n * When an anchor animation occurs, ngAnimate will clone the starting element and position it exactly where the starting\\r\\n * element is located on screen via absolute positioning. The cloned element will be placed inside of the root element\\r\\n * of the application (where ng-app was defined) and all of the CSS classes of the starting element will be applied. The\\r\\n * element will then animate into the `out` and `in` animations and will eventually reach the coordinates and match\\r\\n * the dimensions of the destination element. During the entire animation a CSS class of `.ng-animate-shim` will be applied\\r\\n * to both the starting and destination elements in order to hide them from being visible (the CSS styling for the class\\r\\n * is: `visibility:hidden`). Once the anchor reaches its destination then it will be removed and the destination element\\r\\n * will become visible since the shim class will be removed.\\r\\n *\\r\\n * ### How is the morphing handled?\\r\\n *\\r\\n * CSS Anchoring relies on transitions and keyframes and the internal code is intelligent enough to figure out\\r\\n * what CSS classes differ between the starting element and the destination element. These different CSS classes\\r\\n * will be added/removed on the anchor element and a transition will be applied (the transition that is provided\\r\\n * in the anchor class). Long story short, ngAnimate will figure out what classes to add and remove which will\\r\\n * make the transition of the element as smooth and automatic as possible. Be sure to use simple CSS classes that\\r\\n * do not rely on DOM nesting structure so that the anchor element appears the same as the starting element (since\\r\\n * the cloned element is placed inside of root element which is likely close to the body element).\\r\\n *\\r\\n * Note that if the root element is on the `` element then the cloned node will be placed inside of body.\\r\\n *\\r\\n *\\r\\n * ## Using $animate in your directive code\\r\\n *\\r\\n * So far we've explored how to feed in animations into an Angular application, but how do we trigger animations within our own directives in our application?\\r\\n * By injecting the `$animate` service into our directive code, we can trigger structural and class-based hooks which can then be consumed by animations. Let's\\r\\n * imagine we have a greeting box that shows and hides itself when the data changes\\r\\n *\\r\\n * ```html\\r\\n * Hi there\\r\\n * ```\\r\\n *\\r\\n * ```js\\r\\n * ngModule.directive('greetingBox', ['$animate', function($animate) {\\r\\n * return function(scope, element, attrs) {\\r\\n * attrs.$observe('active', function(value) {\\r\\n * value ? $animate.addClass(element, 'on') : $animate.removeClass(element, 'on');\\r\\n * });\\r\\n * });\\r\\n * }]);\\r\\n * ```\\r\\n *\\r\\n * Now the `on` CSS class is added and removed on the greeting box component. Now if we add a CSS class on top of the greeting box element\\r\\n * in our HTML code then we can trigger a CSS or JS animation to happen.\\r\\n *\\r\\n * ```css\\r\\n * /* normally we would create a CSS class to reference on the element */\\r\\n * greeting-box.on { transition:0.5s linear all; background:green; color:white; }\\r\\n * ```\\r\\n *\\r\\n * The `$animate` service contains a variety of other methods like `enter`, `leave`, `animate` and `setClass`. To learn more about what's\\r\\n * possible be sure to visit the {@link ng.$animate $animate service API page}.\\r\\n *\\r\\n *\\r\\n * ### Preventing Collisions With Third Party Libraries\\r\\n *\\r\\n * Some third-party frameworks place animation duration defaults across many element or className\\r\\n * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which\\r\\n * is expecting actual animations on these elements and has to wait for their completion.\\r\\n *\\r\\n * You can prevent this unwanted behavior by using a prefix on all your animation classes:\\r\\n *\\r\\n * ```css\\r\\n * /* prefixed with animate- */\\r\\n * .animate-fade-add.animate-fade-add-active {\\r\\n * transition:1s linear all;\\r\\n * opacity:0;\\r\\n * }\\r\\n * ```\\r\\n *\\r\\n * You then configure `$animate` to enforce this prefix:\\r\\n *\\r\\n * ```js\\r\\n * $animateProvider.classNameFilter(/animate-/);\\r\\n * ```\\r\\n *\\r\\n * This also may provide your application with a speed boost since only specific elements containing CSS class prefix\\r\\n * will be evaluated for animation when any DOM changes occur in the application.\\r\\n *\\r\\n * ## Callbacks and Promises\\r\\n *\\r\\n * When `$animate` is called it returns a promise that can be used to capture when the animation has ended. Therefore if we were to trigger\\r\\n * an animation (within our directive code) then we can continue performing directive and scope related activities after the animation has\\r\\n * ended by chaining onto the returned promise that animation method returns.\\r\\n *\\r\\n * ```js\\r\\n * // somewhere within the depths of the directive\\r\\n * $animate.enter(element, parent).then(function() {\\r\\n * //the animation has completed\\r\\n * });\\r\\n * ```\\r\\n *\\r\\n * (Note that earlier versions of Angular prior to v1.4 required the promise code to be wrapped using `$scope.$apply(...)`. This is not the case\\r\\n * anymore.)\\r\\n *\\r\\n * In addition to the animation promise, we can also make use of animation-related callbacks within our directives and controller code by registering\\r\\n * an event listener using the `$animate` service. Let's say for example that an animation was triggered on our view\\r\\n * routing controller to hook into that:\\r\\n *\\r\\n * ```js\\r\\n * ngModule.controller('HomePageController', ['$animate', function($animate) {\\r\\n * $animate.on('enter', ngViewElement, function(element) {\\r\\n * // the animation for this route has completed\\r\\n * }]);\\r\\n * }])\\r\\n * ```\\r\\n *\\r\\n * (Note that you will need to trigger a digest within the callback to get angular to notice any scope-related changes.)\\r\\n */\\n\\n /**\\r\\n * @ngdoc service\\r\\n * @name $animate\\r\\n * @kind object\\r\\n *\\r\\n * @description\\r\\n * The ngAnimate `$animate` service documentation is the same for the core `$animate` service.\\r\\n *\\r\\n * Click here {@link ng.$animate to learn more about animations with `$animate`}.\\r\\n */\\n\\n angular.module('ngAnimate', []).directive('ngAnimateSwap', ngAnimateSwapDirective).directive('ngAnimateChildren', $$AnimateChildrenDirective).factory('$$rAFScheduler', $$rAFSchedulerFactory).provider('$$animateQueue', $$AnimateQueueProvider).provider('$$animation', $$AnimationProvider).provider('$animateCss', $AnimateCssProvider).provider('$$animateCssDriver', $$AnimateCssDriverProvider).provider('$$animateJs', $$AnimateJsProvider).provider('$$animateJsDriver', $$AnimateJsDriverProvider);\\n})(window, window.angular);\"","module.exports = \"/*\\r\\n AngularJS v1.5.0\\r\\n (c) 2010-2016 Google, Inc. http://angularjs.org\\r\\n License: MIT\\r\\n*/\\n(function (p, c, n) {\\n 'use strict';\\n\\n function l(b, a, g) {\\n var d = g.baseHref(),\\n k = b[0];\\n return function (b, e, f) {\\n var g, h;\\n f = f || {};\\n h = f.expires;\\n g = c.isDefined(f.path) ? f.path : d;\\n c.isUndefined(e) && (h = \\\"Thu, 01 Jan 1970 00:00:00 GMT\\\", e = \\\"\\\");\\n c.isString(h) && (h = new Date(h));\\n e = encodeURIComponent(b) + \\\"=\\\" + encodeURIComponent(e);\\n e = e + (g ? \\\";path=\\\" + g : \\\"\\\") + (f.domain ? \\\";domain=\\\" + f.domain : \\\"\\\");\\n e += h ? \\\";expires=\\\" + h.toUTCString() : \\\"\\\";\\n e += f.secure ? \\\";secure\\\" : \\\"\\\";\\n f = e.length + 1;\\n 4096 < f && a.warn(\\\"Cookie '\\\" + b + \\\"' possibly not set or overflowed because it was too large (\\\" + f + \\\" > 4096 bytes)!\\\");\\n k.cookie = e;\\n };\\n }\\n\\n c.module(\\\"ngCookies\\\", [\\\"ng\\\"]).provider(\\\"$cookies\\\", [function () {\\n var b = this.defaults = {};\\n this.$get = [\\\"$$cookieReader\\\", \\\"$$cookieWriter\\\", function (a, g) {\\n return {\\n get: function (d) {\\n return a()[d];\\n },\\n getObject: function (d) {\\n return (d = this.get(d)) ? c.fromJson(d) : d;\\n },\\n getAll: function () {\\n return a();\\n },\\n put: function (d, a, m) {\\n g(d, a, m ? c.extend({}, b, m) : b);\\n },\\n putObject: function (d, b, a) {\\n this.put(d, c.toJson(b), a);\\n },\\n remove: function (a, k) {\\n g(a, n, k ? c.extend({}, b, k) : b);\\n }\\n };\\n }];\\n }]);\\n c.module(\\\"ngCookies\\\").factory(\\\"$cookieStore\\\", [\\\"$cookies\\\", function (b) {\\n return {\\n get: function (a) {\\n return b.getObject(a);\\n },\\n put: function (a, c) {\\n b.putObject(a, c);\\n },\\n remove: function (a) {\\n b.remove(a);\\n }\\n };\\n }]);\\n l.$inject = [\\\"$document\\\", \\\"$log\\\", \\\"$browser\\\"];\\n c.module(\\\"ngCookies\\\").provider(\\\"$$cookieWriter\\\", function () {\\n this.$get = l;\\n });\\n})(window, window.angular);\"","module.exports = \"/*\\r\\n AngularJS v1.5.0\\r\\n (c) 2010-2016 Google, Inc. http://angularjs.org\\r\\n License: MIT\\r\\n*/\\n(function (A, e, B) {\\n 'use strict';\\n\\n function C(a) {\\n var c = [];\\n v(c, e.noop).chars(a);\\n return c.join(\\\"\\\");\\n }\\n\\n function h(a, c) {\\n var b = {},\\n d = a.split(\\\",\\\"),\\n l;\\n\\n for (l = 0; l < d.length; l++) b[c ? e.lowercase(d[l]) : d[l]] = !0;\\n\\n return b;\\n }\\n\\n function D(a, c) {\\n null === a || a === B ? a = \\\"\\\" : \\\"string\\\" !== typeof a && (a = \\\"\\\" + a);\\n g.innerHTML = a;\\n var b = 5;\\n\\n do {\\n if (0 === b) throw w(\\\"uinput\\\");\\n b--;\\n 11 >= document.documentMode && n(g);\\n a = g.innerHTML;\\n g.innerHTML = a;\\n } while (a !== g.innerHTML);\\n\\n for (b = g.firstChild; b;) {\\n switch (b.nodeType) {\\n case 1:\\n c.start(b.nodeName.toLowerCase(), E(b.attributes));\\n break;\\n\\n case 3:\\n c.chars(b.textContent);\\n }\\n\\n var d;\\n if (!(d = b.firstChild) && (1 == b.nodeType && c.end(b.nodeName.toLowerCase()), d = b.nextSibling, !d)) for (; null == d;) {\\n b = b.parentNode;\\n if (b === g) break;\\n d = b.nextSibling;\\n 1 == b.nodeType && c.end(b.nodeName.toLowerCase());\\n }\\n b = d;\\n }\\n\\n for (; b = g.firstChild;) g.removeChild(b);\\n }\\n\\n function E(a) {\\n for (var c = {}, b = 0, d = a.length; b < d; b++) {\\n var l = a[b];\\n c[l.name] = l.value;\\n }\\n\\n return c;\\n }\\n\\n function x(a) {\\n return a.replace(/&/g, \\\"&\\\").replace(F, function (a) {\\n var b = a.charCodeAt(0);\\n a = a.charCodeAt(1);\\n return \\\"&#\\\" + (1024 * (b - 55296) + (a - 56320) + 65536) + \\\";\\\";\\n }).replace(G, function (a) {\\n return \\\"&#\\\" + a.charCodeAt(0) + \\\";\\\";\\n }).replace(//g, \\\">\\\");\\n }\\n\\n function v(a, c) {\\n var b = !1,\\n d = e.bind(a, a.push);\\n return {\\n start: function (a, f) {\\n a = e.lowercase(a);\\n !b && H[a] && (b = a);\\n b || !0 !== t[a] || (d(\\\"<\\\"), d(a), e.forEach(f, function (b, f) {\\n var g = e.lowercase(f),\\n h = \\\"img\\\" === a && \\\"src\\\" === g || \\\"background\\\" === g;\\n !0 !== I[g] || !0 === y[g] && !c(b, h) || (d(\\\" \\\"), d(f), d('=\\\"'), d(x(b)), d('\\\"'));\\n }), d(\\\">\\\"));\\n },\\n end: function (a) {\\n a = e.lowercase(a);\\n b || !0 !== t[a] || !0 === z[a] || (d(\\\"\\\"));\\n a == b && (b = !1);\\n },\\n chars: function (a) {\\n b || d(x(a));\\n }\\n };\\n }\\n\\n function n(a) {\\n if (a.nodeType === Node.ELEMENT_NODE) for (var c = a.attributes, b = 0, d = c.length; b < d; b++) {\\n var e = c[b],\\n f = e.name.toLowerCase();\\n if (\\\"xmlns:ns1\\\" === f || 0 === f.indexOf(\\\"ns1:\\\")) a.removeAttributeNode(e), b--, d--;\\n }\\n (c = a.firstChild) && n(c);\\n (c = a.nextSibling) && n(c);\\n }\\n\\n var w = e.$$minErr(\\\"$sanitize\\\"),\\n F = /[\\\\uD800-\\\\uDBFF][\\\\uDC00-\\\\uDFFF]/g,\\n G = /([^\\\\#-~ |!])/g,\\n z = h(\\\"area,br,col,hr,img,wbr\\\"),\\n q = h(\\\"colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr\\\"),\\n k = h(\\\"rp,rt\\\"),\\n u = e.extend({}, k, q),\\n q = e.extend({}, q, h(\\\"address,article,aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul\\\")),\\n k = e.extend({}, k, h(\\\"a,abbr,acronym,b,bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,samp,small,span,strike,strong,sub,sup,time,tt,u,var\\\")),\\n J = h(\\\"circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,radialGradient,rect,stop,svg,switch,text,title,tspan\\\"),\\n H = h(\\\"script,style\\\"),\\n t = e.extend({}, z, q, k, u),\\n y = h(\\\"background,cite,href,longdesc,src,xlink:href\\\"),\\n u = h(\\\"abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,valign,value,vspace,width\\\"),\\n k = h(\\\"accent-height,accumulate,additive,alphabetic,arabic-form,ascent,baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan\\\", !0),\\n I = e.extend({}, y, k, u),\\n g;\\n\\n (function (a) {\\n if (a.document && a.document.implementation) a = a.document.implementation.createHTMLDocument(\\\"inert\\\");else throw w(\\\"noinert\\\");\\n var c = (a.documentElement || a.getDocumentElement()).getElementsByTagName(\\\"body\\\");\\n 1 === c.length ? g = c[0] : (c = a.createElement(\\\"html\\\"), g = a.createElement(\\\"body\\\"), c.appendChild(g), a.appendChild(c));\\n })(A);\\n\\n e.module(\\\"ngSanitize\\\", []).provider(\\\"$sanitize\\\", function () {\\n var a = !1;\\n this.$get = [\\\"$$sanitizeUri\\\", function (c) {\\n a && e.extend(t, J);\\n return function (a) {\\n var d = [];\\n D(a, v(d, function (a, b) {\\n return !/^unsafe:/.test(c(a, b));\\n }));\\n return d.join(\\\"\\\");\\n };\\n }];\\n\\n this.enableSvg = function (c) {\\n return e.isDefined(c) ? (a = c, this) : a;\\n };\\n });\\n e.module(\\\"ngSanitize\\\").filter(\\\"linky\\\", [\\\"$sanitize\\\", function (a) {\\n var c = /((ftp|https?):\\\\/\\\\/|(www\\\\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\\\\S*[^\\\\s.;,(){}<>\\\"\\\\u201d\\\\u2019]/i,\\n b = /^mailto:/i,\\n d = e.$$minErr(\\\"linky\\\"),\\n g = e.isString;\\n return function (f, h, m) {\\n function k(a) {\\n a && p.push(C(a));\\n }\\n\\n function q(a, b) {\\n var c;\\n p.push(\\\"');\\n k(b);\\n p.push(\\\"\\\");\\n }\\n\\n if (null == f || \\\"\\\" === f) return f;\\n if (!g(f)) throw d(\\\"notstring\\\", f);\\n\\n for (var r = f, p = [], s, n; f = r.match(c);) s = f[0], f[2] || f[4] || (s = (f[3] ? \\\"http://\\\" : \\\"mailto:\\\") + s), n = f.index, k(r.substr(0, n)), q(s, f[0].replace(b, \\\"\\\")), r = r.substring(n + f[0].length);\\n\\n k(r);\\n return a(p.join(\\\"\\\"));\\n };\\n }]);\\n})(window, window.angular);\"","module.exports = \"/*! ngStorage 0.3.0 | Copyright (c) 2013 Gias Kay Lee | MIT License */\\n\\\"use strict\\\";\\n\\n!function () {\\n function a(a) {\\n return [\\\"$rootScope\\\", \\\"$window\\\", function (b, c) {\\n for (var d, e, f, g = c[a] || (console.warn(\\\"This browser does not support Web Storage!\\\"), {}), h = {\\n $default: function (a) {\\n for (var b in a) angular.isDefined(h[b]) || (h[b] = a[b]);\\n\\n return h;\\n },\\n $reset: function (a) {\\n for (var b in h) \\\"$\\\" === b[0] || delete h[b];\\n\\n return h.$default(a);\\n }\\n }, i = 0; i < g.length; i++) (f = g.key(i)) && \\\"ngStorage-\\\" === f.slice(0, 10) && (h[f.slice(10)] = angular.fromJson(g.getItem(f)));\\n\\n return d = angular.copy(h), b.$watch(function () {\\n e || (e = setTimeout(function () {\\n if (e = null, !angular.equals(h, d)) {\\n angular.forEach(h, function (a, b) {\\n angular.isDefined(a) && \\\"$\\\" !== b[0] && g.setItem(\\\"ngStorage-\\\" + b, angular.toJson(a)), delete d[b];\\n });\\n\\n for (var a in d) g.removeItem(\\\"ngStorage-\\\" + a);\\n\\n d = angular.copy(h);\\n }\\n }, 100));\\n }), \\\"localStorage\\\" === a && c.addEventListener && c.addEventListener(\\\"storage\\\", function (a) {\\n \\\"ngStorage-\\\" === a.key.slice(0, 10) && (a.newValue ? h[a.key.slice(10)] = angular.fromJson(a.newValue) : delete h[a.key.slice(10)], d = angular.copy(h), b.$apply());\\n }), h;\\n }];\\n }\\n\\n angular.module(\\\"ngStorage\\\", []).factory(\\\"$localStorage\\\", a(\\\"localStorage\\\")).factory(\\\"$sessionStorage\\\", a(\\\"sessionStorage\\\"));\\n}();\"","module.exports = \"/*!\\r\\nangular-xeditable - 0.1.8\\r\\nEdit-in-place for angular.js\\r\\nBuild date: 2014-01-10 \\r\\n*/\\nangular.module(\\\"xeditable\\\", []).value(\\\"editableOptions\\\", {\\n theme: \\\"default\\\",\\n buttons: \\\"right\\\",\\n blurElem: \\\"cancel\\\",\\n blurForm: \\\"ignore\\\",\\n activate: \\\"focus\\\"\\n}), angular.module(\\\"xeditable\\\").directive(\\\"editableBsdate\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableBsdate\\\",\\n inputTpl: ''\\n });\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableBstime\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableBstime\\\",\\n inputTpl: \\\"\\\",\\n render: function () {\\n this.parent.render.call(this);\\n var a = angular.element('
');\\n a.attr(\\\"ng-model\\\", this.inputEl.attr(\\\"ng-model\\\")), this.inputEl.removeAttr(\\\"ng-model\\\"), this.attrs.eNgChange && (a.attr(\\\"ng-change\\\", this.inputEl.attr(\\\"ng-change\\\")), this.inputEl.removeAttr(\\\"ng-change\\\")), this.inputEl.wrap(a);\\n }\\n });\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableCheckbox\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableCheckbox\\\",\\n inputTpl: '',\\n render: function () {\\n this.parent.render.call(this), this.attrs.eTitle && (this.inputEl.wrap(\\\"\\\"), this.inputEl.after(angular.element(\\\"\\\").text(this.attrs.eTitle)));\\n },\\n autosubmit: function () {\\n var a = this;\\n a.inputEl.bind(\\\"change\\\", function () {\\n setTimeout(function () {\\n a.scope.$apply(function () {\\n a.scope.$form.$submit();\\n });\\n }, 500);\\n });\\n }\\n });\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableChecklist\\\", [\\\"editableDirectiveFactory\\\", \\\"editableNgOptionsParser\\\", function (a, b) {\\n return a({\\n directiveName: \\\"editableChecklist\\\",\\n inputTpl: \\\"\\\",\\n useCopy: !0,\\n render: function () {\\n this.parent.render.call(this);\\n var a = b(this.attrs.eNgOptions),\\n c = '';\\n this.inputEl.removeAttr(\\\"ng-model\\\"), this.inputEl.removeAttr(\\\"ng-options\\\"), this.inputEl.html(c);\\n }\\n });\\n}]), function () {\\n var a = \\\"text|email|tel|number|url|search|color|date|datetime|time|month|week\\\".split(\\\"|\\\");\\n angular.forEach(a, function (a) {\\n var b = \\\"editable\\\" + a.charAt(0).toUpperCase() + a.slice(1);\\n angular.module(\\\"xeditable\\\").directive(b, [\\\"editableDirectiveFactory\\\", function (c) {\\n return c({\\n directiveName: b,\\n inputTpl: ''\\n });\\n }]);\\n }), angular.module(\\\"xeditable\\\").directive(\\\"editableRange\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableRange\\\",\\n inputTpl: '',\\n render: function () {\\n this.parent.render.call(this), this.inputEl.after(\\\"{{$data}}\\\");\\n }\\n });\\n }]);\\n}(), angular.module(\\\"xeditable\\\").directive(\\\"editableRadiolist\\\", [\\\"editableDirectiveFactory\\\", \\\"editableNgOptionsParser\\\", function (a, b) {\\n return a({\\n directiveName: \\\"editableRadiolist\\\",\\n inputTpl: \\\"\\\",\\n render: function () {\\n this.parent.render.call(this);\\n var a = b(this.attrs.eNgOptions),\\n c = '';\\n this.inputEl.removeAttr(\\\"ng-model\\\"), this.inputEl.removeAttr(\\\"ng-options\\\"), this.inputEl.html(c);\\n },\\n autosubmit: function () {\\n var a = this;\\n a.inputEl.bind(\\\"change\\\", function () {\\n setTimeout(function () {\\n a.scope.$apply(function () {\\n a.scope.$form.$submit();\\n });\\n }, 500);\\n });\\n }\\n });\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableSelect\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableSelect\\\",\\n inputTpl: \\\"\\\",\\n autosubmit: function () {\\n var a = this;\\n a.inputEl.bind(\\\"change\\\", function () {\\n a.scope.$apply(function () {\\n a.scope.$form.$submit();\\n });\\n });\\n }\\n });\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableTextarea\\\", [\\\"editableDirectiveFactory\\\", function (a) {\\n return a({\\n directiveName: \\\"editableTextarea\\\",\\n inputTpl: \\\"\\\",\\n addListeners: function () {\\n var a = this;\\n a.parent.addListeners.call(a), a.single && \\\"no\\\" !== a.buttons && a.autosubmit();\\n },\\n autosubmit: function () {\\n var a = this;\\n a.inputEl.bind(\\\"keydown\\\", function (b) {\\n (b.ctrlKey || b.metaKey) && 13 === b.keyCode && a.scope.$apply(function () {\\n a.scope.$form.$submit();\\n });\\n });\\n }\\n });\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableController\\\", [\\\"$q\\\", \\\"editableUtils\\\", function (a, b) {\\n function c(a, c, d, e, f, g, h, i, j) {\\n var k,\\n l,\\n m = this;\\n m.scope = a, m.elem = d, m.attrs = c, m.inputEl = null, m.editorEl = null, m.single = !0, m.error = \\\"\\\", m.theme = f[g.theme] || f[\\\"default\\\"], m.parent = {}, m.inputTpl = \\\"\\\", m.directiveName = \\\"\\\", m.useCopy = !1, m.single = null, m.buttons = \\\"right\\\", m.init = function (b) {\\n if (m.single = b, m.name = c.eName || c[m.directiveName], !c[m.directiveName]) throw \\\"You should provide value for `\\\" + m.directiveName + \\\"` in editable element!\\\";\\n k = e(c[m.directiveName]), m.buttons = m.single ? m.attrs.buttons || g.buttons : \\\"no\\\", c.eName && m.scope.$watch(\\\"$data\\\", function (a) {\\n m.scope.$form.$data[c.eName] = a;\\n }), c.onshow && (m.onshow = function () {\\n return m.catchError(e(c.onshow)(a));\\n }), c.onhide && (m.onhide = function () {\\n return e(c.onhide)(a);\\n }), c.oncancel && (m.oncancel = function () {\\n return e(c.oncancel)(a);\\n }), c.onbeforesave && (m.onbeforesave = function () {\\n return m.catchError(e(c.onbeforesave)(a));\\n }), c.onaftersave && (m.onaftersave = function () {\\n return m.catchError(e(c.onaftersave)(a));\\n }), a.$parent.$watch(c[m.directiveName], function () {\\n m.handleEmpty();\\n });\\n }, m.render = function () {\\n var a = m.theme;\\n m.inputEl = angular.element(m.inputTpl), m.controlsEl = angular.element(a.controlsTpl), m.controlsEl.append(m.inputEl), \\\"no\\\" !== m.buttons && (m.buttonsEl = angular.element(a.buttonsTpl), m.submitEl = angular.element(a.submitTpl), m.cancelEl = angular.element(a.cancelTpl), m.buttonsEl.append(m.submitEl).append(m.cancelEl), m.controlsEl.append(m.buttonsEl), m.inputEl.addClass(\\\"editable-has-buttons\\\")), m.errorEl = angular.element(a.errorTpl), m.controlsEl.append(m.errorEl), m.editorEl = angular.element(m.single ? a.formTpl : a.noformTpl), m.editorEl.append(m.controlsEl);\\n\\n for (var d in c.$attr) if (!(d.length <= 1)) {\\n var e = !1,\\n f = d.substring(1, 2);\\n\\n if (\\\"e\\\" === d.substring(0, 1) && f === f.toUpperCase() && (e = d.substring(1), \\\"Form\\\" !== e && \\\"NgSubmit\\\" !== e)) {\\n e = e.substring(0, 1).toLowerCase() + b.camelToDash(e.substring(1));\\n var h = \\\"\\\" === c[d] ? e : c[d];\\n m.inputEl.attr(e, h);\\n }\\n }\\n\\n m.inputEl.addClass(\\\"editable-input\\\"), m.inputEl.attr(\\\"ng-model\\\", \\\"$data\\\"), m.editorEl.addClass(b.camelToDash(m.directiveName)), m.single && (m.editorEl.attr(\\\"editable-form\\\", \\\"$form\\\"), m.editorEl.attr(\\\"blur\\\", m.attrs.blur || (\\\"no\\\" === m.buttons ? \\\"cancel\\\" : g.blurElem))), angular.isFunction(a.postrender) && a.postrender.call(m);\\n }, m.setLocalValue = function () {\\n m.scope.$data = m.useCopy ? angular.copy(k(a.$parent)) : k(a.$parent);\\n }, m.show = function () {\\n return m.setLocalValue(), m.render(), d.after(m.editorEl), i(m.editorEl)(a), m.addListeners(), d.addClass(\\\"editable-hide\\\"), m.onshow();\\n }, m.hide = function () {\\n return m.editorEl.remove(), d.removeClass(\\\"editable-hide\\\"), m.onhide();\\n }, m.cancel = function () {\\n m.oncancel();\\n }, m.addListeners = function () {\\n m.inputEl.bind(\\\"keyup\\\", function (a) {\\n if (m.single) switch (a.keyCode) {\\n case 27:\\n m.scope.$apply(function () {\\n m.scope.$form.$cancel();\\n });\\n }\\n }), m.single && \\\"no\\\" === m.buttons && m.autosubmit(), m.editorEl.bind(\\\"click\\\", function (a) {\\n 1 === a.which && m.scope.$form.$visible && (m.scope.$form._clicked = !0);\\n });\\n }, m.setWaiting = function (a) {\\n a ? (l = !m.inputEl.attr(\\\"disabled\\\") && !m.inputEl.attr(\\\"ng-disabled\\\") && !m.inputEl.attr(\\\"ng-enabled\\\"), l && (m.inputEl.attr(\\\"disabled\\\", \\\"disabled\\\"), m.buttonsEl && m.buttonsEl.find(\\\"button\\\").attr(\\\"disabled\\\", \\\"disabled\\\"))) : l && (m.inputEl.removeAttr(\\\"disabled\\\"), m.buttonsEl && m.buttonsEl.find(\\\"button\\\").removeAttr(\\\"disabled\\\"));\\n }, m.activate = function () {\\n setTimeout(function () {\\n var a = m.inputEl[0];\\n \\\"focus\\\" === g.activate && a.focus && a.focus(), \\\"select\\\" === g.activate && a.select && a.select();\\n }, 0);\\n }, m.setError = function (b) {\\n angular.isObject(b) || (a.$error = b, m.error = b);\\n }, m.catchError = function (a, b) {\\n return angular.isObject(a) && b !== !0 ? j.when(a).then(angular.bind(this, function (a) {\\n this.catchError(a, !0);\\n }), angular.bind(this, function (a) {\\n this.catchError(a, !0);\\n })) : b && angular.isObject(a) && a.status && 200 !== a.status && a.data && angular.isString(a.data) ? (this.setError(a.data), a = a.data) : angular.isString(a) && this.setError(a), a;\\n }, m.save = function () {\\n k.assign(a.$parent, angular.copy(m.scope.$data));\\n }, m.handleEmpty = function () {\\n var b = k(a.$parent),\\n c = null === b || void 0 === b || \\\"\\\" === b || angular.isArray(b) && 0 === b.length;\\n d.toggleClass(\\\"editable-empty\\\", c);\\n }, m.autosubmit = angular.noop, m.onshow = angular.noop, m.onhide = angular.noop, m.oncancel = angular.noop, m.onbeforesave = angular.noop, m.onaftersave = angular.noop;\\n }\\n\\n return c.$inject = [\\\"$scope\\\", \\\"$attrs\\\", \\\"$element\\\", \\\"$parse\\\", \\\"editableThemes\\\", \\\"editableOptions\\\", \\\"$rootScope\\\", \\\"$compile\\\", \\\"$q\\\"], c;\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableDirectiveFactory\\\", [\\\"$parse\\\", \\\"$compile\\\", \\\"editableThemes\\\", \\\"$rootScope\\\", \\\"$document\\\", \\\"editableController\\\", \\\"editableFormController\\\", function (a, b, c, d, e, f, g) {\\n return function (b) {\\n return {\\n restrict: \\\"A\\\",\\n scope: !0,\\n require: [b.directiveName, \\\"?^form\\\"],\\n controller: f,\\n link: function (c, f, h, i) {\\n var j,\\n k = i[0],\\n l = !1;\\n if (i[1]) j = i[1], l = !0;else if (h.eForm) {\\n var m = a(h.eForm)(c);\\n if (m) j = m, l = !0;else for (var n = 0; n < e[0].forms.length; n++) if (e[0].forms[n].name === h.eForm) {\\n j = null, l = !0;\\n break;\\n }\\n }\\n if (angular.forEach(b, function (a, b) {\\n void 0 !== k[b] && (k.parent[b] = k[b]);\\n }), angular.extend(k, b), k.init(!l), c.$editable = k, f.addClass(\\\"editable\\\"), l) {\\n if (j) {\\n if (c.$form = j, !c.$form.$addEditable) throw \\\"Form with editable elements should have `editable-form` attribute.\\\";\\n c.$form.$addEditable(k);\\n } else d.$$editableBuffer = d.$$editableBuffer || {}, d.$$editableBuffer[h.eForm] = d.$$editableBuffer[h.eForm] || [], d.$$editableBuffer[h.eForm].push(k), c.$form = null;\\n } else c.$form = g(), c.$form.$addEditable(k), h.eForm && (c.$parent[h.eForm] = c.$form), h.eForm || (f.addClass(\\\"editable-click\\\"), f.bind(\\\"click\\\", function (a) {\\n a.preventDefault(), a.editable = k, c.$apply(function () {\\n c.$form.$show();\\n });\\n }));\\n }\\n };\\n };\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableFormController\\\", [\\\"$parse\\\", \\\"$document\\\", \\\"$rootScope\\\", \\\"editablePromiseCollection\\\", \\\"editableUtils\\\", function (a, b, c, d, e) {\\n var f = [];\\n b.bind(\\\"click\\\", function (a) {\\n if (1 === a.which) {\\n for (var b = [], d = [], e = 0; e < f.length; e++) f[e]._clicked ? f[e]._clicked = !1 : f[e].$waiting || (\\\"cancel\\\" === f[e]._blur && b.push(f[e]), \\\"submit\\\" === f[e]._blur && d.push(f[e]));\\n\\n (b.length || d.length) && c.$apply(function () {\\n angular.forEach(b, function (a) {\\n a.$cancel();\\n }), angular.forEach(d, function (a) {\\n a.$submit();\\n });\\n });\\n }\\n });\\n var g = {\\n $addEditable: function (a) {\\n this.$editables.push(a), a.elem.bind(\\\"$destroy\\\", angular.bind(this, this.$removeEditable, a)), a.scope.$form || (a.scope.$form = this), this.$visible && a.catchError(a.show());\\n },\\n $removeEditable: function (a) {\\n for (var b = 0; b < this.$editables.length; b++) if (this.$editables[b] === a) return this.$editables.splice(b, 1), void 0;\\n },\\n $show: function () {\\n if (!this.$visible) {\\n this.$visible = !0;\\n var a = d();\\n a.when(this.$onshow()), this.$setError(null, \\\"\\\"), angular.forEach(this.$editables, function (b) {\\n a.when(b.show());\\n }), a.then({\\n onWait: angular.bind(this, this.$setWaiting),\\n onTrue: angular.bind(this, this.$activate),\\n onFalse: angular.bind(this, this.$activate),\\n onString: angular.bind(this, this.$activate)\\n }), setTimeout(angular.bind(this, function () {\\n this._clicked = !1, -1 === e.indexOf(f, this) && f.push(this);\\n }), 0);\\n }\\n },\\n $activate: function (a) {\\n var b;\\n\\n if (this.$editables.length) {\\n if (angular.isString(a)) for (b = 0; b < this.$editables.length; b++) if (this.$editables[b].name === a) return this.$editables[b].activate(), void 0;\\n\\n for (b = 0; b < this.$editables.length; b++) if (this.$editables[b].error) return this.$editables[b].activate(), void 0;\\n\\n this.$editables[0].activate();\\n }\\n },\\n $hide: function () {\\n this.$visible && (this.$visible = !1, this.$onhide(), angular.forEach(this.$editables, function (a) {\\n a.hide();\\n }), e.arrayRemove(f, this));\\n },\\n $cancel: function () {\\n this.$visible && (this.$oncancel(), angular.forEach(this.$editables, function (a) {\\n a.cancel();\\n }), this.$hide());\\n },\\n $setWaiting: function (a) {\\n this.$waiting = !!a, angular.forEach(this.$editables, function (b) {\\n b.setWaiting(!!a);\\n });\\n },\\n $setError: function (a, b) {\\n angular.forEach(this.$editables, function (c) {\\n a && c.name !== a || c.setError(b);\\n });\\n },\\n $submit: function () {\\n function a(a) {\\n var b = d();\\n b.when(this.$onbeforesave()), b.then({\\n onWait: angular.bind(this, this.$setWaiting),\\n onTrue: a ? angular.bind(this, this.$save) : angular.bind(this, this.$hide),\\n onFalse: angular.bind(this, this.$hide),\\n onString: angular.bind(this, this.$activate)\\n });\\n }\\n\\n if (!this.$waiting) {\\n this.$setError(null, \\\"\\\");\\n var b = d();\\n angular.forEach(this.$editables, function (a) {\\n b.when(a.onbeforesave());\\n }), b.then({\\n onWait: angular.bind(this, this.$setWaiting),\\n onTrue: angular.bind(this, a, !0),\\n onFalse: angular.bind(this, a, !1),\\n onString: angular.bind(this, this.$activate)\\n });\\n }\\n },\\n $save: function () {\\n angular.forEach(this.$editables, function (a) {\\n a.save();\\n });\\n var a = d();\\n a.when(this.$onaftersave()), angular.forEach(this.$editables, function (b) {\\n a.when(b.onaftersave());\\n }), a.then({\\n onWait: angular.bind(this, this.$setWaiting),\\n onTrue: angular.bind(this, this.$hide),\\n onFalse: angular.bind(this, this.$hide),\\n onString: angular.bind(this, this.$activate)\\n });\\n },\\n $onshow: angular.noop,\\n $oncancel: angular.noop,\\n $onhide: angular.noop,\\n $onbeforesave: angular.noop,\\n $onaftersave: angular.noop\\n };\\n return function () {\\n return angular.extend({\\n $editables: [],\\n $visible: !1,\\n $waiting: !1,\\n $data: {},\\n _clicked: !1,\\n _blur: null\\n }, g);\\n };\\n}]), angular.module(\\\"xeditable\\\").directive(\\\"editableForm\\\", [\\\"$rootScope\\\", \\\"$parse\\\", \\\"editableFormController\\\", \\\"editableOptions\\\", function (a, b, c, d) {\\n return {\\n restrict: \\\"A\\\",\\n require: [\\\"form\\\"],\\n compile: function () {\\n return {\\n pre: function (b, d, e, f) {\\n var g,\\n h = f[0];\\n e.editableForm ? b[e.editableForm] && b[e.editableForm].$show ? (g = b[e.editableForm], angular.extend(h, g)) : (g = c(), b[e.editableForm] = g, angular.extend(g, h)) : (g = c(), angular.extend(h, g));\\n var i = a.$$editableBuffer,\\n j = h.$name;\\n j && i && i[j] && (angular.forEach(i[j], function (a) {\\n g.$addEditable(a);\\n }), delete i[j]);\\n },\\n post: function (a, c, e, f) {\\n var g;\\n g = e.editableForm && a[e.editableForm] && a[e.editableForm].$show ? a[e.editableForm] : f[0], e.onshow && (g.$onshow = angular.bind(g, b(e.onshow), a)), e.onhide && (g.$onhide = angular.bind(g, b(e.onhide), a)), e.oncancel && (g.$oncancel = angular.bind(g, b(e.oncancel), a)), e.shown && b(e.shown)(a) && g.$show(), g._blur = e.blur || d.blurForm, e.ngSubmit || e.submit || (e.onbeforesave && (g.$onbeforesave = function () {\\n return b(e.onbeforesave)(a, {\\n $data: g.$data\\n });\\n }), e.onaftersave && (g.$onaftersave = function () {\\n return b(e.onaftersave)(a, {\\n $data: g.$data\\n });\\n }), c.bind(\\\"submit\\\", function (b) {\\n b.preventDefault(), a.$apply(function () {\\n g.$submit();\\n });\\n })), c.bind(\\\"click\\\", function (a) {\\n 1 === a.which && g.$visible && (g._clicked = !0);\\n });\\n }\\n };\\n }\\n };\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editablePromiseCollection\\\", [\\\"$q\\\", function (a) {\\n function b() {\\n return {\\n promises: [],\\n hasFalse: !1,\\n hasString: !1,\\n when: function (b, c) {\\n if (b === !1) this.hasFalse = !0;else if (!c && angular.isObject(b)) this.promises.push(a.when(b));else {\\n if (!angular.isString(b)) return;\\n this.hasString = !0;\\n }\\n },\\n then: function (b) {\\n function c() {\\n h.hasString || h.hasFalse ? !h.hasString && h.hasFalse ? e() : f() : d();\\n }\\n\\n b = b || {};\\n var d = b.onTrue || angular.noop,\\n e = b.onFalse || angular.noop,\\n f = b.onString || angular.noop,\\n g = b.onWait || angular.noop,\\n h = this;\\n this.promises.length ? (g(!0), a.all(this.promises).then(function (a) {\\n g(!1), angular.forEach(a, function (a) {\\n h.when(a, !0);\\n }), c();\\n }, function () {\\n g(!1), f();\\n })) : c();\\n }\\n };\\n }\\n\\n return b;\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableUtils\\\", [function () {\\n return {\\n indexOf: function (a, b) {\\n if (a.indexOf) return a.indexOf(b);\\n\\n for (var c = 0; c < a.length; c++) if (b === a[c]) return c;\\n\\n return -1;\\n },\\n arrayRemove: function (a, b) {\\n var c = this.indexOf(a, b);\\n return c >= 0 && a.splice(c, 1), b;\\n },\\n camelToDash: function (a) {\\n var b = /[A-Z]/g;\\n return a.replace(b, function (a, b) {\\n return (b ? \\\"-\\\" : \\\"\\\") + a.toLowerCase();\\n });\\n },\\n dashToCamel: function (a) {\\n var b = /([\\\\:\\\\-\\\\_]+(.))/g,\\n c = /^moz([A-Z])/;\\n return a.replace(b, function (a, b, c, d) {\\n return d ? c.toUpperCase() : c;\\n }).replace(c, \\\"Moz$1\\\");\\n }\\n };\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableNgOptionsParser\\\", [function () {\\n function a(a) {\\n var c;\\n if (!(c = a.match(b))) throw \\\"ng-options parse error\\\";\\n var d,\\n e = c[2] || c[1],\\n f = c[4] || c[6],\\n g = c[5],\\n h = (c[3] || \\\"\\\", c[2] ? c[1] : f),\\n i = c[7],\\n j = c[8],\\n k = j ? c[8] : null;\\n return void 0 === g ? (d = f + \\\" in \\\" + i, void 0 !== j && (d += \\\" track by \\\" + k)) : d = \\\"(\\\" + g + \\\", \\\" + f + \\\") in \\\" + i, {\\n ngRepeat: d,\\n locals: {\\n valueName: f,\\n keyName: g,\\n valueFn: h,\\n displayFn: e\\n }\\n };\\n }\\n\\n var b = /^\\\\s*(.*?)(?:\\\\s+as\\\\s+(.*?))?(?:\\\\s+group\\\\s+by\\\\s+(.*))?\\\\s+for\\\\s+(?:([\\\\$\\\\w][\\\\$\\\\w]*)|(?:\\\\(\\\\s*([\\\\$\\\\w][\\\\$\\\\w]*)\\\\s*,\\\\s*([\\\\$\\\\w][\\\\$\\\\w]*)\\\\s*\\\\)))\\\\s+in\\\\s+(.*?)(?:\\\\s+track\\\\s+by\\\\s+(.*?))?$/;\\n return a;\\n}]), angular.module(\\\"xeditable\\\").factory(\\\"editableThemes\\\", function () {\\n var a = {\\n \\\"default\\\": {\\n formTpl: '
',\\n noformTpl: '',\\n controlsTpl: '',\\n inputTpl: \\\"\\\",\\n errorTpl: '
',\\n buttonsTpl: '',\\n submitTpl: '',\\n cancelTpl: ''\\n },\\n bs2: {\\n formTpl: '
',\\n noformTpl: '',\\n controlsTpl: '
',\\n inputTpl: \\\"\\\",\\n errorTpl: '
',\\n buttonsTpl: '',\\n submitTpl: '',\\n cancelTpl: ''\\n },\\n bs3: {\\n formTpl: '
',\\n noformTpl: '',\\n controlsTpl: '
',\\n inputTpl: \\\"\\\",\\n errorTpl: '
',\\n buttonsTpl: '',\\n submitTpl: '',\\n cancelTpl: '',\\n buttonsClass: \\\"\\\",\\n inputClass: \\\"\\\",\\n postrender: function () {\\n switch (this.directiveName) {\\n case \\\"editableText\\\":\\n case \\\"editableSelect\\\":\\n case \\\"editableTextarea\\\":\\n case \\\"editableEmail\\\":\\n case \\\"editableTel\\\":\\n case \\\"editableNumber\\\":\\n case \\\"editableUrl\\\":\\n case \\\"editableSearch\\\":\\n case \\\"editableDate\\\":\\n case \\\"editableDatetime\\\":\\n case \\\"editableTime\\\":\\n case \\\"editableMonth\\\":\\n case \\\"editableWeek\\\":\\n if (this.inputEl.addClass(\\\"form-control\\\"), this.theme.inputClass) {\\n if (this.inputEl.attr(\\\"multiple\\\") && (\\\"input-sm\\\" === this.theme.inputClass || \\\"input-lg\\\" === this.theme.inputClass)) break;\\n this.inputEl.addClass(this.theme.inputClass);\\n }\\n\\n }\\n\\n this.buttonsEl && this.theme.buttonsClass && this.buttonsEl.find(\\\"button\\\").addClass(this.theme.buttonsClass);\\n }\\n }\\n };\\n return a;\\n});\"","module.exports = \"(function() {\\n 'use strict';\\n angular.module('ngMask', []);\\n})();(function() {\\n 'use strict';\\n angular.module('ngMask')\\n .directive('mask', ['$log', '$timeout', 'MaskService', function($log, $timeout, MaskService) {\\n return {\\n restrict: 'A',\\n require: 'ngModel',\\n compile: function($element, $attrs) { \\n if (!$attrs.mask || !$attrs.ngModel) {\\n $log.info('Mask and ng-model attributes are required!');\\n return;\\n }\\n\\n var maskService = MaskService.create();\\n var timeout;\\n var promise;\\n\\n function setSelectionRange(selectionStart){\\n if (typeof selectionStart !== 'number') {\\n return;\\n }\\n\\n // using $timeout:\\n // it should run after the DOM has been manipulated by Angular\\n // and after the browser renders (which may cause flicker in some cases)\\n $timeout.cancel(timeout);\\n timeout = $timeout(function(){\\n var selectionEnd = selectionStart + 1;\\n var input = $element[0];\\n\\n if (input.setSelectionRange) {\\n input.focus();\\n input.setSelectionRange(selectionStart, selectionEnd);\\n } else if (input.createTextRange) {\\n var range = input.createTextRange();\\n\\n range.collapse(true);\\n range.moveEnd('character', selectionEnd);\\n range.moveStart('character', selectionStart);\\n range.select();\\n }\\n });\\n }\\n\\n return {\\n pre: function($scope, $element, $attrs, controller) {\\n promise = maskService.generateRegex({\\n mask: $attrs.mask,\\n // repeat mask expression n times\\n repeat: ($attrs.repeat || $attrs.maskRepeat),\\n // clean model value - without divisors\\n clean: (($attrs.clean || $attrs.maskClean) === 'true'),\\n // limit length based on mask length\\n limit: (($attrs.limit || $attrs.maskLimit || 'true') === 'true'),\\n // how to act with a wrong value\\n restrict: ($attrs.restrict || $attrs.maskRestrict || 'select'), //select, reject, accept\\n // set validity mask\\n validate: (($attrs.validate || $attrs.maskValidate || 'true') === 'true'),\\n // default model value\\n model: $attrs.ngModel,\\n // default input value\\n value: $attrs.ngValue\\n });\\n },\\n post: function($scope, $element, $attrs, controller) {\\n var timeout;\\n var options = maskService.getOptions();\\n\\n function parseViewValue(value) {\\n var untouchedValue = value;\\n options = maskService.getOptions();\\n // set default value equal 0\\n value = value || '';\\n\\n // get view value object\\n var viewValue = maskService.getViewValue(value);\\n\\n // get mask without question marks\\n var maskWithoutOptionals = options['maskWithoutOptionals'] || '';\\n\\n // get view values capped\\n // used on view\\n var viewValueWithDivisors = viewValue.withDivisors(true);\\n // used on model\\n var viewValueWithoutDivisors = viewValue.withoutDivisors(true);\\n\\n try {\\n // get current regex\\n var regex = maskService.getRegex(viewValueWithDivisors.length - 1);\\n var fullRegex = maskService.getRegex(maskWithoutOptionals.length - 1);\\n\\n // current position is valid\\n var validCurrentPosition = regex.test(viewValueWithDivisors) || fullRegex.test(viewValueWithDivisors);\\n\\n // difference means for select option\\n var diffValueAndViewValueLengthIsOne = (value.length - viewValueWithDivisors.length) === 1;\\n var diffMaskAndViewValueIsGreaterThanZero = (maskWithoutOptionals.length - viewValueWithDivisors.length) > 0;\\n\\n if (options.restrict !== 'accept') {\\n if (options.restrict === 'select' && (!validCurrentPosition || diffValueAndViewValueLengthIsOne)) {\\n var lastCharInputed = value[(value.length-1)];\\n var lastCharGenerated = viewValueWithDivisors[(viewValueWithDivisors.length-1)];\\n\\n if ((lastCharInputed !== lastCharGenerated) && diffMaskAndViewValueIsGreaterThanZero) {\\n viewValueWithDivisors = viewValueWithDivisors + lastCharInputed;\\n }\\n\\n var wrongPosition = maskService.getFirstWrongPosition(viewValueWithDivisors);\\n if (angular.isDefined(wrongPosition)) {\\n setSelectionRange(wrongPosition);\\n }\\n } else if (options.restrict === 'reject' && !validCurrentPosition) {\\n viewValue = maskService.removeWrongPositions(viewValueWithDivisors);\\n viewValueWithDivisors = viewValue.withDivisors(true);\\n viewValueWithoutDivisors = viewValue.withoutDivisors(true);\\n\\n // setSelectionRange(viewValueWithDivisors.length);\\n }\\n }\\n\\n if (!options.limit) {\\n viewValueWithDivisors = viewValue.withDivisors(false);\\n viewValueWithoutDivisors = viewValue.withoutDivisors(false);\\n }\\n\\n // Set validity\\n if (options.validate && controller.$dirty) {\\n if (fullRegex.test(viewValueWithDivisors) || controller.$isEmpty(untouchedValue)) {\\n controller.$setValidity('mask', true);\\n } else {\\n controller.$setValidity('mask', false);\\n }\\n }\\n\\n // Update view and model values\\n if(value !== viewValueWithDivisors){\\n controller.$setViewValue(angular.copy(viewValueWithDivisors), 'input');\\n controller.$render();\\n }\\n } catch (e) {\\n $log.error('[mask - parseViewValue]');\\n throw e;\\n }\\n\\n // Update model, can be different of view value\\n if (options.clean) {\\n return viewValueWithoutDivisors;\\n } else {\\n return viewValueWithDivisors;\\n }\\n }\\n\\n var callParseViewValue = function() {\\n parseViewValue();\\n\\n controller.$parsers.push(parseViewValue);\\n\\n // $evalAsync from a directive\\n // it should run after the DOM has been manipulated by Angular\\n // but before the browser renders\\n if(options.value) {\\n $scope.$evalAsync(function($scope) {\\n controller.$setViewValue(angular.copy(options.value), 'input');\\n controller.$render();\\n });\\n }\\n }\\n\\n $element.on('click input paste keyup', function() {\\n timeout = $timeout(function() {\\n // Manual debounce to prevent multiple execution\\n $timeout.cancel(timeout);\\n\\n parseViewValue($element.val());\\n $scope.$apply();\\n }, 100);\\n });\\n\\n // Register the watch to observe remote loading or promised data\\n // Deregister calling returned function\\n var watcher = $scope.$watch($attrs.ngModel, function (newValue, oldValue) {\\n if (angular.isDefined(newValue)) {\\n parseViewValue(newValue);\\n watcher();\\n }\\n });\\n\\n $scope.$watch(function () {\\n return [$attrs.mask];\\n }, function() {\\n promise = maskService.generateRegex({\\n mask: $attrs.mask,\\n // repeat mask expression n times\\n repeat: ($attrs.repeat || $attrs.maskRepeat),\\n // clean model value - without divisors\\n clean: (($attrs.clean || $attrs.maskClean) === 'true'),\\n // limit length based on mask length\\n limit: (($attrs.limit || $attrs.maskLimit || 'true') === 'true'),\\n // how to act with a wrong value\\n restrict: ($attrs.restrict || $attrs.maskRestrict || 'select'), //select, reject, accept\\n // set validity mask\\n validate: (($attrs.validate || $attrs.maskValidate || 'true') === 'true'),\\n // default model value\\n model: $attrs.ngModel,\\n // default input value\\n value: $attrs.ngValue\\n }).then(function() {\\n $element.triggerHandler('click');\\n });\\n\\n promise.then(callParseViewValue);\\n }, true);\\n\\n promise.then(callParseViewValue);\\n }\\n }\\n }\\n }\\n }]);\\n})();\\n(function() {\\n 'use strict';\\n angular.module('ngMask')\\n .factory('MaskService', ['$q', 'OptionalService', 'UtilService', function($q, OptionalService, UtilService) {\\n function create() {\\n var options;\\n var maskWithoutOptionals;\\n var maskWithoutOptionalsLength = 0;\\n var maskWithoutOptionalsAndDivisorsLength = 0;\\n var optionalIndexes = [];\\n var optionalDivisors = {};\\n var optionalDivisorsCombinations = [];\\n var divisors = [];\\n var divisorElements = {};\\n var regex = [];\\n var patterns = {\\n '9': /[0-9]/,\\n '8': /[0-8]/,\\n '7': /[0-7]/,\\n '6': /[0-6]/,\\n '5': /[0-5]/,\\n '4': /[0-4]/,\\n '3': /[0-3]/,\\n '2': /[0-2]/,\\n '1': /[0-1]/,\\n '0': /[0]/,\\n '*': /./,\\n 'w': /\\\\w/,\\n 'W': /\\\\W/,\\n 'd': /\\\\d/,\\n 'D': /\\\\D/,\\n 's': /\\\\s/,\\n 'S': /\\\\S/,\\n 'b': /\\\\b/,\\n 'A': /[A-Z]/,\\n 'a': /[a-z]/,\\n 'Z': /[A-ZÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/,\\n 'z': /[a-zçáàãâéèêẽíìĩîóòôõúùũüû]/,\\n '@': /[a-zA-Z]/,\\n '#': /[a-zA-ZçáàãâéèêẽíìĩîóòôõúùũüûÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/,\\n '%': /[0-9a-zA-ZçáàãâéèêẽíìĩîóòôõúùũüûÇÀÁÂÃÈÉÊẼÌÍÎĨÒÓÔÕÙÚÛŨ]/\\n };\\n\\n // REGEX\\n\\n function generateIntermetiateElementRegex(i, forceOptional) {\\n var charRegex;\\n try {\\n var element = maskWithoutOptionals[i];\\n var elementRegex = patterns[element];\\n var hasOptional = isOptional(i);\\n\\n if (elementRegex) {\\n charRegex = '(' + elementRegex.source + ')';\\n } else { // is a divisor\\n if (!isDivisor(i)) {\\n divisors.push(i);\\n divisorElements[i] = element;\\n }\\n\\n charRegex = '(' + '\\\\\\\\' + element + ')';\\n }\\n } catch (e) {\\n throw e;\\n }\\n\\n if (hasOptional || forceOptional) {\\n charRegex += '?';\\n }\\n\\n return new RegExp(charRegex);\\n }\\n\\n function generateIntermetiateRegex(i, forceOptional) {\\n\\n\\n var elementRegex\\n var elementOptionalRegex;\\n try {\\n var intermetiateElementRegex = generateIntermetiateElementRegex(i, forceOptional);\\n elementRegex = intermetiateElementRegex;\\n\\n var hasOptional = isOptional(i);\\n var currentRegex = intermetiateElementRegex.source;\\n\\n if (hasOptional && ((i+1) < maskWithoutOptionalsLength)) {\\n var intermetiateRegex = generateIntermetiateRegex((i+1), true).elementOptionalRegex();\\n currentRegex += intermetiateRegex.source;\\n }\\n\\n elementOptionalRegex = new RegExp(currentRegex);\\n } catch (e) {\\n throw e;\\n }\\n return {\\n elementRegex: function() {\\n return elementRegex;\\n },\\n elementOptionalRegex: function() {\\n // from element regex, gets the flow of regex until first not optional\\n return elementOptionalRegex;\\n }\\n };\\n }\\n\\n function generateRegex(opts) {\\n var deferred = $q.defer();\\n maskWithoutOptionals = null;\\n maskWithoutOptionalsLength = 0;\\n maskWithoutOptionalsAndDivisorsLength = 0;\\n optionalIndexes = [];\\n optionalDivisors = {};\\n optionalDivisorsCombinations = [];\\n divisors = [];\\n divisorElements = {};\\n regex = [];\\n options = opts;\\n\\n try {\\n var mask = opts['mask'];\\n var repeat = opts['repeat'];\\n\\n if (!mask)\\n return;\\n\\n if (repeat) {\\n mask = Array((parseInt(repeat)+1)).join(mask);\\n }\\n\\n optionalIndexes = OptionalService.getOptionals(mask).fromMaskWithoutOptionals();\\n options['maskWithoutOptionals'] = maskWithoutOptionals = OptionalService.removeOptionals(mask);\\n maskWithoutOptionalsLength = maskWithoutOptionals.length;\\n\\n var cumulativeRegex;\\n for (var i=0; i= divisor) {\\n break;\\n }\\n\\n if (optionalDivisors[divisor]) {\\n optionalDivisors[divisor] = optionalDivisors[divisor].concat(divisor-j);\\n } else {\\n optionalDivisors[divisor] = [(divisor-j)];\\n }\\n\\n // get the original divisor for alternative divisor\\n divisorElements[(divisor-j)] = divisorElements[divisor];\\n }\\n }\\n }\\n\\n function removeDivisors(value) {\\n value = value.toString();\\n try {\\n if (divisors.length > 0 && value) {\\n var keys = Object.keys(divisorElements);\\n var elments = [];\\n\\n for (var i = keys.length - 1; i >= 0; i--) {\\n var divisor = divisorElements[keys[i]];\\n if (divisor) {\\n elments.push(divisor);\\n }\\n }\\n\\n elments = UtilService.uniqueArray(elments);\\n\\n // remove if it is not pattern\\n var regex = new RegExp(('[' + '\\\\\\\\' + elments.join('\\\\\\\\') + ']'), 'g');\\n return value.replace(regex, '');\\n } else {\\n return value;\\n }\\n } catch (e) {\\n throw e;\\n }\\n }\\n\\n function insertDivisors(array, combination) {\\n function insert(array, output) {\\n var out = output;\\n for (var i=0; i 0) {\\n var lazyArguments = [];\\n var optionalDivisorsKeys = Object.keys(optionalDivisors);\\n\\n // get all optional divisors as array of arrays [[], [], []...]\\n for (var i=0; i= 0; i--) {\\n var outputClone = angular.copy(output);\\n outputClone = insertDivisors(outputClone, optionalDivisorsCombinations[i]);\\n\\n // try validation\\n var viewValueWithDivisors = outputClone.join('');\\n var regex = getRegex(maskWithoutOptionals.length - 1);\\n\\n if (regex.test(viewValueWithDivisors)) {\\n defaultDivisors = false;\\n output = outputClone;\\n break;\\n }\\n }\\n }\\n\\n if (defaultDivisors) {\\n output = insertDivisors(output, divisors);\\n }\\n\\n return output.join('');\\n }\\n\\n // MASK\\n\\n function getOptions() {\\n return options;\\n }\\n\\n function getViewValue(value) {\\n try {\\n var outputWithoutDivisors = removeDivisors(value);\\n var output = tryDivisorConfiguration(outputWithoutDivisors);\\n\\n return {\\n withDivisors: function(capped) {\\n if (capped) {\\n return output.substr(0, maskWithoutOptionalsLength);\\n } else {\\n return output;\\n }\\n },\\n withoutDivisors: function(capped) {\\n if (capped) {\\n return outputWithoutDivisors.substr(0, maskWithoutOptionalsAndDivisorsLength);\\n } else {\\n return outputWithoutDivisors;\\n }\\n }\\n };\\n } catch (e) {\\n throw e;\\n }\\n }\\n\\n // SELECTOR\\n\\n function getWrongPositions(viewValueWithDivisors, onlyFirst) {\\n var pos = [];\\n\\n if (!viewValueWithDivisors) {\\n return 0;\\n }\\n\\n for (var i=0; i -1;\\n } catch (e) {\\n throw e;\\n }\\n\\n return output;\\n }\\n\\n function uniqueArray(array) {\\n var u = {};\\n var a = [];\\n\\n for (var i = 0, l = array.length; i < l; ++i) {\\n if(u.hasOwnProperty(array[i])) {\\n continue;\\n }\\n\\n a.push(array[i]);\\n u[array[i]] = 1;\\n }\\n\\n return a;\\n }\\n\\n return {\\n lazyProduct: lazyProduct,\\n inArray: inArray,\\n uniqueArray: uniqueArray\\n }\\n }]);\\n})();\"","module.exports = \"!function(a){\\\"use strict\\\";\\\"function\\\"==typeof define&&define.amd?define([\\\"jquery\\\"],a):a(\\\"object\\\"==typeof exports?require(\\\"jquery\\\"):jQuery)}(function(a){\\\"use strict\\\";a.Zebra_DatePicker=function(b,c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q={always_visible:!1,container:a(\\\"body\\\"),custom_classes:!1,days:[\\\"Sunday\\\",\\\"Monday\\\",\\\"Tuesday\\\",\\\"Wednesday\\\",\\\"Thursday\\\",\\\"Friday\\\",\\\"Saturday\\\"],days_abbr:!1,default_position:\\\"above\\\",direction:0,disabled_dates:!1,enabled_dates:!1,first_day_of_week:1,format:\\\"Y-m-d\\\",header_captions:{days:\\\"F, Y\\\",months:\\\"Y\\\",years:\\\"Y1 - Y2\\\"},header_navigation:[\\\"«\\\",\\\"»\\\"],icon_position:\\\"right\\\",inside:!0,lang_clear_date:\\\"Clear date\\\",months:[\\\"January\\\",\\\"February\\\",\\\"March\\\",\\\"April\\\",\\\"May\\\",\\\"June\\\",\\\"July\\\",\\\"August\\\",\\\"September\\\",\\\"October\\\",\\\"November\\\",\\\"December\\\"],months_abbr:!1,offset:[5,-5],open_icon_only:!1,pair:!1,readonly_element:!0,select_other_months:!1,show_clear_date:0,show_icon:!0,show_other_months:!0,show_select_today:\\\"Today\\\",show_week_number:!1,start_date:!1,strict:!1,view:\\\"days\\\",weekend_days:[0,6],zero_pad:!1,onChange:null,onClear:null,onOpen:null,onClose:null,onSelect:null},R=this;R.settings={};var S=a(b),T=function(b){if(N=Math.floor(65536*(1+Math.random())).toString(16),!b){R.settings=a.extend({},Q,c);for(var y in S.data())0===y.indexOf(\\\"zdp_\\\")&&(y=y.replace(/^zdp\\\\_/,\\\"\\\"),void 0!==Q[y]&&(R.settings[y]=\\\"pair\\\"==y?a(S.data(\\\"zdp_\\\"+y)):S.data(\\\"zdp_\\\"+y)))}R.settings.readonly_element&&S.attr(\\\"readonly\\\",\\\"readonly\\\");var E={days:[\\\"d\\\",\\\"j\\\",\\\"D\\\"],months:[\\\"F\\\",\\\"m\\\",\\\"M\\\",\\\"n\\\",\\\"t\\\"],years:[\\\"o\\\",\\\"Y\\\",\\\"y\\\"]},F=!1,G=!1,T=!1,W=null;for(W in E)a.each(E[W],function(a,b){R.settings.format.indexOf(b)>-1&&(\\\"days\\\"==W?F=!0:\\\"months\\\"==W?G=!0:\\\"years\\\"==W&&(T=!0))});H=F&&G&&T?[\\\"years\\\",\\\"months\\\",\\\"days\\\"]:!F&&G&&T?[\\\"years\\\",\\\"months\\\"]:F&&G&&!T?[\\\"months\\\",\\\"days\\\"]:F||G||!T?F||!G||T?[\\\"years\\\",\\\"months\\\",\\\"days\\\"]:[\\\"months\\\"]:[\\\"years\\\"],-1==a.inArray(R.settings.view,H)&&(R.settings.view=H[H.length-1]),x=[],w=[],O={},P=[];var X;for(var Y in R.settings.custom_classes)R.settings.custom_classes.hasOwnProperty(Y)&&P.push(Y);for(var Z=0;Z<2+P.length;Z++)X=0===Z?R.settings.disabled_dates:1==Z?R.settings.enabled_dates:R.settings.custom_classes[P[Z-2]],a.isArray(X)&&X.length>0&&a.each(X,function(){for(var b=this.split(\\\" \\\"),c=0;4>c;c++){b[c]||(b[c]=\\\"*\\\"),b[c]=b[c].indexOf(\\\",\\\")>-1?b[c].split(\\\",\\\"):new Array(b[c]);for(var d=0;d-1){var e=b[c][d].match(/^([0-9]+)\\\\-([0-9]+)/);if(null!==e){for(var f=ia(e[1]);f<=ia(e[2]);f++)-1==a.inArray(f,b[c])&&b[c].push(f+\\\"\\\");b[c].splice(d,1)}}for(d=0;d0||a.isArray(R.settings.direction)&&(($=U(R.settings.direction[0]))||R.settings.direction[0]===!0||ca(R.settings.direction[0])&&R.settings.direction[0]>0)&&((_=U(R.settings.direction[1]))||R.settings.direction[1]===!1||ca(R.settings.direction[1])&&R.settings.direction[1]>=0))z=$?$:new Date(p,o,q+ia(a.isArray(R.settings.direction)?R.settings.direction[0]===!0?0:R.settings.direction[0]:R.settings.direction)),o=z.getMonth(),p=z.getFullYear(),q=z.getDate(),_&&+_>=+z?A=_:!_&&R.settings.direction[1]!==!1&&a.isArray(R.settings.direction)&&(A=new Date(p,o,q+ia(R.settings.direction[1]))),A&&(D=A.getMonth(),C=A.getFullYear(),B=A.getDate());else if(!a.isArray(R.settings.direction)&&ca(R.settings.direction)&&ia(R.settings.direction)<0||a.isArray(R.settings.direction)&&(R.settings.direction[0]===!1||ca(R.settings.direction[0])&&R.settings.direction[0]<0)&&(($=U(R.settings.direction[1]))||ca(R.settings.direction[1])&&R.settings.direction[1]>=0))A=new Date(p,o,q+ia(a.isArray(R.settings.direction)?R.settings.direction[0]===!1?0:R.settings.direction[0]:R.settings.direction)),D=A.getMonth(),C=A.getFullYear(),B=A.getDate(),$&&+A>+$?z=$:!$&&a.isArray(R.settings.direction)&&(z=new Date(C,D,B-ia(R.settings.direction[1]))),z&&(o=z.getMonth(),p=z.getFullYear(),q=z.getDate());else if(a.isArray(R.settings.disabled_dates)&&R.settings.disabled_dates.length>0)for(var ga in x)if(\\\"*\\\"==x[ga][0]&&\\\"*\\\"==x[ga][1]&&\\\"*\\\"==x[ga][2]&&\\\"*\\\"==x[ga][3]){var ka=[];if(a.each(w,function(){var a=this;\\\"*\\\"!=a[2][0]&&ka.push(parseInt(a[2][0]+(\\\"*\\\"==a[1][0]?\\\"12\\\":ha(a[1][0],2))+(\\\"*\\\"==a[0][0]?\\\"*\\\"==a[1][0]?\\\"31\\\":new Date(a[2][0],a[1][0],0).getDate():ha(a[0][0],2)),10))}),ka.sort(),ka.length>0){var ma=(ka[0]+\\\"\\\").match(/([0-9]{4})([0-9]{2})([0-9]{2})/);p=parseInt(ma[1],10),o=parseInt(ma[2],10)-1,q=parseInt(ma[3],10)}break}if(ba(p,o,q)){for(;ba(p);)z?(p++,o=0):(p--,o=11);for(;ba(p,o);)z?(o++,q=1):(o--,q=new Date(p,o+1,0).getDate()),o>11?(p++,o=0,q=1):0>o&&(p--,o=11,q=new Date(p,o+1,0).getDate());for(;ba(p,o,q);)z?q++:q--,aa=new Date(p,o,q),p=aa.getFullYear(),o=aa.getMonth(),q=aa.getDate();aa=new Date(p,o,q),p=aa.getFullYear(),o=aa.getMonth(),q=aa.getDate()}var na=U(S.val()||(R.settings.start_date?R.settings.start_date:\\\"\\\"));if(na&&R.settings.strict&&ba(na.getFullYear(),na.getMonth(),na.getDate())&&S.val(\\\"\\\"),b||void 0===z&&void 0===na||ja(void 0!==na?na:z),!R.settings.always_visible){if(!b){if(R.settings.show_icon){\\\"firefox\\\"==la.name&&S.is('input[type=\\\"text\\\"]')&&\\\"inline\\\"==S.css(\\\"display\\\")&&S.css(\\\"display\\\",\\\"inline-block\\\");var oa=a('').css({display:S.css(\\\"display\\\"),position:\\\"static\\\"==S.css(\\\"position\\\")?\\\"relative\\\":S.css(\\\"position\\\"),\\\"float\\\":S.css(\\\"float\\\"),top:S.css(\\\"top\\\"),right:S.css(\\\"right\\\"),bottom:S.css(\\\"bottom\\\"),left:S.css(\\\"left\\\")});S.wrap(oa).css({position:\\\"relative\\\",top:\\\"auto\\\",right:\\\"auto\\\",bottom:\\\"auto\\\",left:\\\"auto\\\"}),f=a(''),R.icon=f,I=R.settings.open_icon_only?f:f.add(S)}else I=S;I.bind(\\\"click\\\",function(a){a.preventDefault(),S.attr(\\\"disabled\\\")||(e.hasClass(\\\"dp_visible\\\")?R.hide():R.show())}),!R.settings.readonly_element&&R.settings.pair&&S.bind(\\\"blur.Zebra_DatePicker_\\\"+N,function(){var b;(b=U(a(this).val()))&&!ba(b.getFullYear(),b.getMonth(),b.getDate())&&ja(b)}),void 0!==f&&f.insertAfter(S)}if(void 0!==f){f.attr(\\\"style\\\",\\\"\\\"),R.settings.inside&&f.addClass(\\\"Zebra_DatePicker_Icon_Inside_\\\"+(\\\"right\\\"==R.settings.icon_position?\\\"Right\\\":\\\"Left\\\"));var pa=S.outerWidth(),qa=S.outerHeight(),ra=parseInt(S.css(\\\"marginLeft\\\"),10)||0,sa=parseInt(S.css(\\\"marginTop\\\"),10)||0,ta=(f.outerWidth(),f.outerHeight()),ua=parseInt(f.css(\\\"marginLeft\\\"),10)||0;parseInt(f.css(\\\"marginRight\\\"),10)||0;R.settings.inside?(f.css(\\\"top\\\",sa+(qa-ta)/2),\\\"right\\\"==R.settings.icon_position?f.css(\\\"right\\\",0):f.css(\\\"left\\\",0)):f.css({top:sa+(qa-ta)/2,left:ra+pa+ua}),f.removeClass(\\\" Zebra_DatePicker_Icon_Disabled\\\"),\\\"disabled\\\"==S.attr(\\\"disabled\\\")&&f.addClass(\\\"Zebra_DatePicker_Icon_Disabled\\\")}}if(L=R.settings.show_select_today!==!1&&a.inArray(\\\"days\\\",H)>-1&&!ba(m,l,n)?R.settings.show_select_today:!1,b)return a(\\\".dp_previous\\\",e).html(R.settings.header_navigation[0]),a(\\\".dp_next\\\",e).html(R.settings.header_navigation[1]),a(\\\".dp_clear\\\",e).html(R.settings.lang_clear_date),void a(\\\".dp_today\\\",e).html(R.settings.show_select_today);a(window).bind(\\\"resize.Zebra_DatePicker_\\\"+N+\\\", orientationchange.Zebra_DatePicker_\\\"+N,function(){R.hide(),void 0!==f&&(clearTimeout(M),M=setTimeout(function(){R.update()},100))});var va='
'+R.settings.header_navigation[0]+' '+R.settings.header_navigation[1]+'
\\\"+L+'\\\"+R.settings.lang_clear_date+\\\"
\\\";e=a(va),R.datepicker=e,g=a(\\\"table.dp_header\\\",e),h=a(\\\"table.dp_daypicker\\\",e),i=a(\\\"table.dp_monthpicker\\\",e),j=a(\\\"table.dp_yearpicker\\\",e),K=a(\\\"table.dp_footer\\\",e),J=a(\\\"td.dp_today\\\",K),k=a(\\\"td.dp_clear\\\",K),R.settings.always_visible?S.attr(\\\"disabled\\\")||(R.settings.always_visible.append(e),R.show()):R.settings.container.append(e),e.delegate(\\\"td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)\\\",\\\"mouseover\\\",function(){a(this).addClass(\\\"dp_hover\\\")}).delegate(\\\"td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)\\\",\\\"mouseout\\\",function(){a(this).removeClass(\\\"dp_hover\\\")}),V(a(\\\"td\\\",g)),a(\\\".dp_previous\\\",g).bind(\\\"click\\\",function(){\\\"months\\\"==d?s--:\\\"years\\\"==d?s-=12:--r<0&&(r=11,s--),ea()}),a(\\\".dp_caption\\\",g).bind(\\\"click\\\",function(){d=\\\"days\\\"==d?a.inArray(\\\"months\\\",H)>-1?\\\"months\\\":a.inArray(\\\"years\\\",H)>-1?\\\"years\\\":\\\"days\\\":\\\"months\\\"==d?a.inArray(\\\"years\\\",H)>-1?\\\"years\\\":a.inArray(\\\"days\\\",H)>-1?\\\"days\\\":\\\"months\\\":a.inArray(\\\"days\\\",H)>-1?\\\"days\\\":a.inArray(\\\"months\\\",H)>-1?\\\"months\\\":\\\"years\\\",ea()}),a(\\\".dp_next\\\",g).bind(\\\"click\\\",function(){\\\"months\\\"==d?s++:\\\"years\\\"==d?s+=12:12==++r&&(r=0,s++),ea()}),h.delegate(\\\"td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)\\\",\\\"click\\\",function(){R.settings.select_other_months&&a(this).attr(\\\"class\\\")&&null!==(ma=a(this).attr(\\\"class\\\").match(/date\\\\_([0-9]{4})(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])/))?fa(ma[1],ma[2]-1,ma[3],\\\"days\\\",a(this)):fa(s,r,ia(a(this).html()),\\\"days\\\",a(this))}),i.delegate(\\\"td:not(.dp_disabled)\\\",\\\"click\\\",function(){var b=a(this).attr(\\\"class\\\").match(/dp\\\\_month\\\\_([0-9]+)/);r=ia(b[1]),-1==a.inArray(\\\"days\\\",H)?fa(s,r,1,\\\"months\\\",a(this)):(d=\\\"days\\\",R.settings.always_visible&&S.val(\\\"\\\"),ea())}),j.delegate(\\\"td:not(.dp_disabled)\\\",\\\"click\\\",function(){s=ia(a(this).html()),-1==a.inArray(\\\"months\\\",H)?fa(s,1,1,\\\"years\\\",a(this)):(d=\\\"months\\\",R.settings.always_visible&&S.val(\\\"\\\"),ea())}),a(J).bind(\\\"click\\\",function(b){b.preventDefault(),fa(m,l,n,\\\"days\\\",a(\\\".dp_current\\\",h)),R.settings.always_visible&&R.show(),R.hide()}),a(k).bind(\\\"click\\\",function(b){b.preventDefault(),S.val(\\\"\\\"),R.settings.always_visible?(t=null,u=null,v=null,a(\\\"td.dp_selected\\\",e).removeClass(\\\"dp_selected\\\")):(t=null,u=null,v=null,r=null,s=null),R.hide(),R.settings.onClear&&\\\"function\\\"==typeof R.settings.onClear&&R.settings.onClear.call(S,S)}),R.settings.always_visible||(a(document).bind(\\\"mousedown.Zebra_DatePicker_\\\"+N+\\\", touchstart.Zebra_DatePicker_\\\"+N,function(b){if(e.hasClass(\\\"dp_visible\\\")){if(R.settings.show_icon&&a(b.target).get(0)===f.get(0))return!0;0===a(b.target).parents().filter(\\\".Zebra_DatePicker\\\").length&&R.hide()}}),a(document).bind(\\\"keyup.Zebra_DatePicker_\\\"+N,function(a){e.hasClass(\\\"dp_visible\\\")&&27==a.which&&R.hide()})),ea()};R.clear_date=function(){a(k).trigger(\\\"click\\\")},R.destroy=function(){void 0!==R.icon&&R.icon.remove(),R.datepicker.remove(),a(document).unbind(\\\"keyup.Zebra_DatePicker_\\\"+N),a(document).unbind(\\\"mousedown.Zebra_DatePicker_\\\"+N),a(window).unbind(\\\"resize.Zebra_DatePicker_\\\"+N),a(window).unbind(\\\"orientationchange.Zebra_DatePicker_\\\"+N),S.removeData(\\\"Zebra_DatePicker\\\")},R.hide=function(){R.settings.always_visible||(aa(\\\"hide\\\"),e.removeClass(\\\"dp_visible\\\").addClass(\\\"dp_hidden\\\"),R.settings.onClose&&\\\"function\\\"==typeof R.settings.onClose&&R.settings.onClose.call(S,S))},R.set_date=function(a){var b;(b=U(a))&&!ba(b.getFullYear(),b.getMonth(),b.getDate())&&(S.val(a),ja(a))},R.show=function(){d=R.settings.view;var b=U(S.val()||(R.settings.start_date?R.settings.start_date:\\\"\\\"));if(b?(u=b.getMonth(),r=b.getMonth(),v=b.getFullYear(),s=b.getFullYear(),t=b.getDate(),ba(v,u,t)&&(R.settings.strict&&S.val(\\\"\\\"),r=o,s=p)):(r=o,s=p),ea(),R.settings.always_visible)e.removeClass(\\\"dp_hidden\\\").addClass(\\\"dp_visible\\\");else{if(R.settings.container.is(\\\"body\\\")){var c=e.outerWidth(),g=e.outerHeight(),h=(void 0!==f?f.offset().left+f.outerWidth(!0):S.offset().left+S.outerWidth(!0))+R.settings.offset[0],i=(void 0!==f?f.offset().top:S.offset().top)-g+R.settings.offset[1],j=a(window).width(),k=a(window).height(),l=a(window).scrollTop(),m=a(window).scrollLeft();\\\"below\\\"==R.settings.default_position&&(i=(void 0!==f?f.offset().top:S.offset().top)+R.settings.offset[1]),h+c>m+j&&(h=m+j-c),m>h&&(h=m),i+g>l+k&&(i=l+k-g),l>i&&(i=l),e.css({left:h,top:i})}else e.css({left:0,top:0});e.removeClass(\\\"dp_hidden\\\").addClass(\\\"dp_visible\\\"),aa()}R.settings.onOpen&&\\\"function\\\"==typeof R.settings.onOpen&&R.settings.onOpen.call(S,S)},R.update=function(b){R.original_direction&&(R.original_direction=R.direction),R.settings=a.extend(R.settings,b),T(!0)};var U=function(b){if(b+=\\\"\\\",\\\"\\\"!==a.trim(b)){for(var c=W(R.settings.format),d=[\\\"d\\\",\\\"D\\\",\\\"j\\\",\\\"l\\\",\\\"N\\\",\\\"S\\\",\\\"w\\\",\\\"F\\\",\\\"m\\\",\\\"M\\\",\\\"n\\\",\\\"Y\\\",\\\"y\\\"],e=[],f=[],g=null,h=null,i=0;i-1&&e.push({character:d[i],position:g});if(e.sort(function(a,b){return a.position-b.position}),a.each(e,function(a,b){switch(b.character){case\\\"d\\\":f.push(\\\"0[1-9]|[12][0-9]|3[01]\\\");break;case\\\"D\\\":f.push(\\\"[a-z]{3}\\\");break;case\\\"j\\\":f.push(\\\"[1-9]|[12][0-9]|3[01]\\\");break;case\\\"l\\\":f.push(\\\"[a-z]+\\\");break;case\\\"N\\\":f.push(\\\"[1-7]\\\");break;case\\\"S\\\":f.push(\\\"st|nd|rd|th\\\");break;case\\\"w\\\":f.push(\\\"[0-6]\\\");break;case\\\"F\\\":f.push(\\\"[a-z]+\\\");break;case\\\"m\\\":f.push(\\\"0[1-9]|1[012]+\\\");break;case\\\"M\\\":f.push(\\\"[a-z]{3}\\\");break;case\\\"n\\\":f.push(\\\"[1-9]|1[012]\\\");break;case\\\"Y\\\":f.push(\\\"[0-9]{4}\\\");break;case\\\"y\\\":f.push(\\\"[0-9]{2}\\\")}}),f.length&&(e.reverse(),a.each(e,function(a,b){c=c.replace(b.character,\\\"(\\\"+f[f.length-a-1]+\\\")\\\")}),f=new RegExp(\\\"^\\\"+c+\\\"$\\\",\\\"ig\\\"),h=f.exec(b))){var j,k=new Date,l=1,m=k.getMonth()+1,n=k.getFullYear(),o=[\\\"Sunday\\\",\\\"Monday\\\",\\\"Tuesday\\\",\\\"Wednesday\\\",\\\"Thursday\\\",\\\"Friday\\\",\\\"Saturday\\\"],p=[\\\"January\\\",\\\"February\\\",\\\"March\\\",\\\"April\\\",\\\"May\\\",\\\"June\\\",\\\"July\\\",\\\"August\\\",\\\"September\\\",\\\"October\\\",\\\"November\\\",\\\"December\\\"],q=!0;if(e.reverse(),a.each(e,function(b,c){if(!q)return!0;switch(c.character){case\\\"m\\\":case\\\"n\\\":m=ia(h[b+1]);break;case\\\"d\\\":case\\\"j\\\":l=ia(h[b+1]);break;case\\\"D\\\":case\\\"l\\\":case\\\"F\\\":case\\\"M\\\":j=\\\"D\\\"==c.character||\\\"l\\\"==c.character?R.settings.days:R.settings.months,q=!1,a.each(j,function(a,d){if(q)return!0;if(h[b+1].toLowerCase()==d.substring(0,\\\"D\\\"==c.character||\\\"M\\\"==c.character?3:d.length).toLowerCase()){switch(c.character){case\\\"D\\\":h[b+1]=o[a].substring(0,3);break;case\\\"l\\\":h[b+1]=o[a];break;case\\\"F\\\":h[b+1]=p[a],m=a+1;break;case\\\"M\\\":h[b+1]=p[a].substring(0,3),m=a+1}q=!0}});break;case\\\"Y\\\":n=ia(h[b+1]);break;case\\\"y\\\":n=\\\"19\\\"+ia(h[b+1])}}),q){var r=new Date(n,(m||1)-1,l||1);if(r.getFullYear()==n&&r.getDate()==(l||1)&&r.getMonth()==(m||1)-1)return r}}return!1}},V=function(a){\\\"firefox\\\"==la.name?a.css(\\\"MozUserSelect\\\",\\\"none\\\"):\\\"explorer\\\"==la.name?a.bind(\\\"selectstart\\\",function(){return!1}):a.mousedown(function(){return!1})},W=function(a){return a.replace(/([-.,*+?^${}()|[\\\\]\\\\/\\\\\\\\])/g,\\\"\\\\\\\\$1\\\")},X=function(b){for(var c=\\\"\\\",d=b.getDate(),e=b.getDay(),f=R.settings.days[e],g=b.getMonth()+1,h=R.settings.months[g-1],i=b.getFullYear()+\\\"\\\",j=0;je?7+e:e,da(R.settings.header_captions.days);var f=\\\"\\\";R.settings.show_week_number&&(f+=\\\"\\\"+R.settings.show_week_number+\\\"\\\");for(var g=0;7>g;g++)f+=\\\"\\\"+(a.isArray(R.settings.days_abbr)&&void 0!==R.settings.days_abbr[(R.settings.first_day_of_week+g)%7]?R.settings.days_abbr[(R.settings.first_day_of_week+g)%7]:R.settings.days[(R.settings.first_day_of_week+g)%7].substr(0,2))+\\\"\\\";for(f+=\\\"\\\",g=0;42>g;g++){g>0&&g%7===0&&(f+=\\\"\\\"),g%7===0&&R.settings.show_week_number&&(f+=''+ka(new Date(s,r,g-e+1))+\\\"\\\");var i=g-e+1;if(R.settings.select_other_months&&(e>g||i>b)){var j=new Date(s,r,i),k=j.getFullYear(),o=j.getMonth(),p=j.getDate();j=k+ha(o+1,2)+ha(p,2)}if(e>g)f+=''+(R.settings.select_other_months||R.settings.show_other_months?ha(d-e+g+1,R.settings.zero_pad?2:0):\\\" \\\")+\\\"\\\";else if(i>b)f+=''+(R.settings.select_other_months||R.settings.show_other_months?ha(i-b,R.settings.zero_pad?2:0):\\\" \\\")+\\\"\\\";else{var q=(R.settings.first_day_of_week+g)%7,w=\\\"\\\",x=_(s,r,i);ba(s,r,i)?(a.inArray(q,R.settings.weekend_days)>-1?w=\\\"dp_weekend_disabled\\\":w+=\\\" dp_disabled\\\",r==l&&s==m&&n==i&&(w+=\\\" dp_disabled_current\\\"),\\\"\\\"!=x&&(w+=\\\" \\\"+x+\\\"_disabled\\\")):(a.inArray(q,R.settings.weekend_days)>-1&&(w=\\\"dp_weekend\\\"),r==u&&s==v&&t==i&&(w+=\\\" dp_selected\\\"),r==l&&s==m&&n==i&&(w+=\\\" dp_current\\\"),\\\"\\\"!=x&&(w+=\\\" \\\"+x)),f+=\\\"\\\"+((R.settings.zero_pad?ha(i,2):i)||\\\" \\\")+\\\"\\\"}}f+=\\\"\\\",h.html(a(f)),R.settings.always_visible&&(E=a(\\\"td:not(.dp_disabled, .dp_weekend_disabled, .dp_not_in_month, .dp_week_number)\\\",h)),h.show()},Z=function(){da(R.settings.header_captions.months);for(var b=\\\"\\\",c=0;12>c;c++){c>0&&c%3===0&&(b+=\\\"\\\");var d=\\\"dp_month_\\\"+c;ba(s,c)?d+=\\\" dp_disabled\\\":u!==!1&&u==c&&s==v?d+=\\\" dp_selected\\\":l==c&&m==s&&(d+=\\\" dp_current\\\"),b+=''+(a.isArray(R.settings.months_abbr)&&void 0!==R.settings.months_abbr[c]?R.settings.months_abbr[c]:R.settings.months[c].substr(0,3))+\\\"\\\"}b+=\\\"\\\",i.html(a(b)),R.settings.always_visible&&(F=a(\\\"td:not(.dp_disabled)\\\",i)),i.show()},$=function(){da(R.settings.header_captions.years);for(var b=\\\"\\\",c=0;12>c;c++){c>0&&c%3===0&&(b+=\\\"\\\");var d=\\\"\\\";ba(s-7+c)?d+=\\\" dp_disabled\\\":v&&v==s-7+c?d+=\\\" dp_selected\\\":m==s-7+c&&(d+=\\\" dp_current\\\"),b+=\\\"\\\"+(s-7+c)+\\\"\\\"}b+=\\\"\\\",j.html(a(b)),R.settings.always_visible&&(G=a(\\\"td:not(.dp_disabled)\\\",j)),j.show()},_=function(b,c,d){var e,f,g;\\\"undefined\\\"!=typeof c&&(c+=1);for(f in P)if(e=P[f],g=!1,a.each(O[e],function(){if(!g){var f=this;if((a.inArray(b,f[2])>-1||a.inArray(\\\"*\\\",f[2])>-1)&&(\\\"undefined\\\"!=typeof c&&a.inArray(c,f[1])>-1||a.inArray(\\\"*\\\",f[1])>-1)&&(\\\"undefined\\\"!=typeof d&&a.inArray(d,f[0])>-1||a.inArray(\\\"*\\\",f[0])>-1)){if(\\\"*\\\"==f[3])return g=e;var h=new Date(b,c-1,d).getDay();if(a.inArray(h,f[3])>-1)return g=e}}}),g)return g;return g||\\\"\\\"},aa=function(b){if(\\\"explorer\\\"==la.name&&6==la.version){if(!y){var c=ia(e.css(\\\"zIndex\\\"))-1;y=a(\\\"